#include "cuda_driver_wrapper.h"
#include "cuda_context_wrapper.h"
#include "cuda_driver_types.h"
#include "cuda_to_maca_mcr_adaptor.h"
#include "mc_runtime_api.h"
#include "mc_runtime_api_deprecated.h"
#include "mc_runtime_types.h"
#include "mcc/mcc_global.h"
#include <map>

thread_local bool g_hasContextBeenCreated = false;

void switchEnvToMaca() __attribute__((constructor(301)));
void switchEnvToMaca()
{
    std::map<std::string, std::pair<std::string, int>> deal_env = {
        {"CUDA_LAUNCH_BLOCKING", {"MACA_LAUNCH_BLOCKING", 1}},
        {"CUDA_VISIBLE_DEVICES", {"MACA_VISIBLE_DEVICES", 1}},
        {"CUDA_CACHE_DISABLE", {"MACA_CACHE_DISABLE", 1}},
        {"CUDA_CACHE_PATH", {"MACA_CACHE_PATH", 1}},
        {"CUDA_CACHE_MAXSIZE", {"MACA_CACHE_MAXSIZE", 1}},
        {"CUDA_DEVICE_ORDER", {"MACA_DEVICE_ORDER", 1}},
        {"CUDA_MODULE_LOADING", {"MACA_MODULE_LOADING", 1}}};
    for (auto &env : deal_env) {
        char *cuda_env_value = getenv(env.first.c_str());
        if (cuda_env_value != nullptr) {
            if (env.second.first.length()) {
                setenv(env.second.first.c_str(), cuda_env_value, env.second.second);
            }
        }
    }
}

mcDrvError_t mcErrorTomcDrvError(mcError_t mcError)
{
    switch (mcError) {
    case mcSuccess:
        return MC_SUCCESS;
    case mcErrorInvalidValue:
        return MC_ERROR_INVALID_VALUE;
    case mcErrorMemoryAllocation:
        return MC_ERROR_OUT_OF_MEMORY;
    case mcErrorInitializationError:
        return MC_ERROR_NOT_INITIALIZED;
    case mcErrorDeinitialized:
        return MC_ERROR_DEINITIALIZED;
    case mcErrorProfilerDisabled:
        return MC_ERROR_PROFILER_DISABLED;
    case mcErrorProfilerNotInitialized:
        return MC_ERROR_PROFILER_NOT_INITIALIZED;
    case mcErrorProfilerAlreadyStarted:
        return MC_ERROR_PROFILER_ALREADY_STARTED;
    case mcErrorProfilerAlreadyStopped:
        return MC_ERROR_PROFILER_ALREADY_STOPPED;
    case mcErrorStubLibrary:
        return MC_ERROR_STUB_LIBRARY;
    case mcErrorNoDevice:
        return MC_ERROR_NO_DEVICE;
    case mcErrorInvalidDevice:
        return MC_ERROR_INVALID_DEVICE;
    case mcErrorDeviceNotLicensed:
        return MC_ERROR_DEVICE_NOT_LICENSED;
    case mcErrorInvalidKernelImage:
        return MC_ERROR_INVALID_IMAGE;
    case mcErrorDeviceUninitialized:
        return MC_ERROR_INVALID_CONTEXT;
    case mcErrorContextAlreadyCurrent:
        return MC_ERROR_CONTEXT_ALREADY_CURRENT;
    case mcErrorMapBufferObjectFailed:
        return MC_ERROR_MAP_FAILED;
    case mcErrorUnmapBufferObjectFailed:
        return MC_ERROR_UNMAP_FAILED;
    case mcErrorArrayIsMapped:
        return MC_ERROR_ARRAY_IS_MAPPED;
    case mcErrorAlreadyMapped:
        return MC_ERROR_ALREADY_MAPPED;
    case mcErrorNoKernelImageForDevice:
        return MC_ERROR_NO_BINARY_FOR_GPU;
    case mcErrorAlreadyAcquired:
        return MC_ERROR_ALREADY_ACQUIRED;
    case mcErrorNotMapped:
        return MC_ERROR_NOT_MAPPED;
    case mcErrorNotMappedAsArray:
        return MC_ERROR_NOT_MAPPED_AS_ARRAY;
    case mcErrorNotMappedAsPointer:
        return MC_ERROR_NOT_MAPPED_AS_POINTER;
    case mcErrorECCUncorrectable:
        return MC_ERROR_ECC_UNCORRECTABLE;
    case mcErrorUnsupportedLimit:
        return MC_ERROR_UNSUPPORTED_LIMIT;
    case mcErrorDeviceAlreadyInUse:
        return MC_ERROR_CONTEXT_ALREADY_IN_USE;
    case mcErrorPeerAccessUnsupported:
        return MC_ERROR_PEER_ACCESS_UNSUPPORTED;
    case mcErrorInvalidKernelFile:
        return MC_ERROR_INVALID_KERNEL_FILE;
    case mcErrorInvalidGraphicsContext:
        return MC_ERROR_INVALID_GRAPHICS_CONTEXT;
    case mcErrorMxlinkUncorrectable:
        return MC_ERROR_MXLINK_UNCORRECTABLE;
    case mcErrorJitCompilerNotFound:
        return MC_ERROR_JIT_COMPILER_NOT_FOUND;
    case mcErrorUnsupportedKernelVersion:
        return MC_ERROR_UNSUPPORTED_KERNEL_VERSION;
    case mcErrorJitCompilationDisabled:
        return MC_ERROR_JIT_COMPILATION_DISABLED;
    case mcErrorUnsupportedExecAffinity:
        return MC_ERROR_UNSUPPORTED_EXEC_AFFINITY;
    case mcErrorInvalidSource:
        return MC_ERROR_INVALID_SOURCE;
    case mcErrorFileNotFound:
        return MC_ERROR_FILE_NOT_FOUND;
    case mcErrorSharedObjectSymbolNotFound:
        return MC_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND;
    case mcErrorSharedObjectInitFailed:
        return MC_ERROR_SHARED_OBJECT_INIT_FAILED;
    case mcErrorOperatingSystem:
        return MC_ERROR_OPERATING_SYSTEM;
    case mcErrorInvalidResourceHandle:
        return MC_ERROR_INVALID_HANDLE;
    case mcErrorIllegalState:
        return MC_ERROR_ILLEGAL_STATE;
    case mcErrorSymbolNotFound:
        return MC_ERROR_NOT_FOUND;
    case mcErrorNotReady:
        return MC_ERROR_NOT_READY;
    case mcErrorIllegalAddress:
        return MC_ERROR_ILLEGAL_ADDRESS;
    case mcErrorLaunchOutOfResources:
        return MC_ERROR_LAUNCH_OUT_OF_RESOURCES;
    case mcErrorLaunchTimeout:
        return MC_ERROR_LAUNCH_TIMEOUT;
    case mcErrorLaunchIncompatibleTexturing:
        return MC_ERROR_LAUNCH_INCOMPATIBLE_TEXTURING;
    case mcErrorPeerAccessAlreadyEnabled:
        return MC_ERROR_PEER_ACCESS_ALREADY_ENABLED;
    case mcErrorPeerAccessNotEnabled:
        return MC_ERROR_PEER_ACCESS_NOT_ENABLED;
    case mcErrorSetOnActiveProcess:
        return MC_ERROR_PRIMARY_CONTEXT_ACTIVE;
    case mcErrorContextIsDestroyed:
        return MC_ERROR_CONTEXT_IS_DESTROYED;
    case mcErrorAssert:
        return MC_ERROR_ASSERT;
    case mcErrorTooManyPeers:
        return MC_ERROR_TOO_MANY_PEERS;
    case mcErrorHostMemoryAlreadyRegistered:
        return MC_ERROR_HOST_MEMORY_ALREADY_REGISTERED;
    case mcErrorHostMemoryNotRegistered:
        return MC_ERROR_HOST_MEMORY_NOT_REGISTERED;
    case mcErrorHardwareStackError:
        return MC_ERROR_HARDWARE_STACK_ERROR;
    case mcErrorIllegalInstruction:
        return MC_ERROR_ILLEGAL_INSTRUCTION;
    case mcErrorMisalignedAddress:
        return MC_ERROR_MISALIGNED_ADDRESS;
    case mcErrorInvalidAddressSpace:
        return MC_ERROR_INVALID_ADDRESS_SPACE;
    case mcErrorInvalidPc:
        return MC_ERROR_INVALID_PC;
    case mcErrorLaunchFailure:
        return MC_ERROR_LAUNCH_FAILED;
    case mcErrorCooperativeLaunchTooLarge:
        return MC_ERROR_COOPERATIVE_LAUNCH_TOO_LARGE;
    case mcErrorNotPermitted:
        return MC_ERROR_NOT_PERMITTED;
    case mcErrorNotSupported:
        return MC_ERROR_NOT_SUPPORTED;
    case mcErrorSystemNotReady:
        return MC_ERROR_SYSTEM_NOT_READY;
    case mcErrorSystemDriverMismatch:
        return MC_ERROR_SYSTEM_DRIVER_MISMATCH;
    case mcErrorCompatNotSupportedOnDevice:
        return MC_ERROR_COMPAT_NOT_SUPPORTED_ON_DEVICE;
    case mcErrorMpsConnectionFailed:
        return MC_ERROR_MPS_CONNECTION_FAILED;
    case mcErrorMpsRpcFailure:
        return MC_ERROR_MPS_RPC_FAILURE;
    case mcErrorMpsServerNotReady:
        return MC_ERROR_MPS_SERVER_NOT_READY;
    case mcErrorMpsMaxClientsReached:
        return MC_ERROR_MPS_MAX_CLIENTS_REACHED;
    case mcErrorMpsMaxConnectionsReached:
        return MC_ERROR_MPS_MAX_CONNECTIONS_REACHED;
    case mcErrorStreamCaptureUnsupported:
        return MC_ERROR_STREAM_CAPTURE_UNSUPPORTED;
    case mcErrorStreamCaptureInvalidated:
        return MC_ERROR_STREAM_CAPTURE_INVALIDATED;
    case mcErrorStreamCaptureMerge:
        return MC_ERROR_STREAM_CAPTURE_MERGE;
    case mcErrorStreamCaptureUnmatched:
        return MC_ERROR_STREAM_CAPTURE_UNMATCHED;
    case mcErrorStreamCaptureUnjoined:
        return MC_ERROR_STREAM_CAPTURE_UNJOINED;
    case mcErrorStreamCaptureIsolation:
        return MC_ERROR_STREAM_CAPTURE_ISOLATION;
    case mcErrorStreamCaptureImplicit:
        return MC_ERROR_STREAM_CAPTURE_IMPLICIT;
    case mcErrorCapturedEvent:
        return MC_ERROR_CAPTURED_EVENT;
    case mcErrorStreamCaptureWrongThread:
        return MC_ERROR_STREAM_CAPTURE_WRONG_THREAD;
    case mcErrorTimeout:
        return MC_ERROR_TIMEOUT;
    case mcErrorGraphExecUpdateFailure:
        return MC_ERROR_GRAPH_EXEC_UPDATE_FAILURE;
    case mcErrorExternalDevice:
        return MC_ERROR_EXTERNAL_DEVICE;
    case mcErrorUnknown:
        return MC_ERROR_UNKNOWN;
    default:
        return MC_ERROR_UNKNOWN;
    }
}

//---------------------------------------------------------------------------//
// Error Handling
//---------------------------------------------------------------------------//
mcDrvError_t wcuGetErrorName(mcDrvError_t error, const char **pStr)
{
    switch (error) {
    case MC_SUCCESS:
        *pStr = "CUDA_SUCCESS";
        break;
    case MC_ERROR_INVALID_VALUE:
        *pStr = "CUDA_ERROR_INVALID_VALUE";
        break;
    case MC_ERROR_OUT_OF_MEMORY:
        *pStr = "CUDA_ERROR_OUT_OF_MEMORY";
        break;
    case MC_ERROR_NOT_INITIALIZED:
        *pStr = "CUDA_ERROR_NOT_INITIALIZED";
        break;
    case MC_ERROR_DEINITIALIZED:
        *pStr = "CUDA_ERROR_DEINITIALIZED";
        break;
    case MC_ERROR_PROFILER_DISABLED:
        *pStr = "CUDA_ERROR_PROFILER_DISABLED";
        break;
    case MC_ERROR_PROFILER_NOT_INITIALIZED:
        *pStr = "CUDA_ERROR_PROFILER_NOT_INITIALIZED";
        break;
    case MC_ERROR_PROFILER_ALREADY_STARTED:
        *pStr = "CUDA_ERROR_PROFILER_ALREADY_STARTED";
        break;
    case MC_ERROR_PROFILER_ALREADY_STOPPED:
        *pStr = "CUDA_ERROR_PROFILER_ALREADY_STOPPED";
        break;
    case MC_ERROR_STUB_LIBRARY:
        *pStr = "CUDA_ERROR_STUB_LIBRARY";
        break;
    case MC_ERROR_NO_DEVICE:
        *pStr = "CUDA_ERROR_NO_DEVICE";
        break;
    case MC_ERROR_INVALID_DEVICE:
        *pStr = "CUDA_ERROR_INVALID_DEVICE";
        break;
    case MC_ERROR_DEVICE_NOT_LICENSED:
        *pStr = "CUDA_ERROR_DEVICE_NOT_LICENSED";
        break;
    case MC_ERROR_INVALID_IMAGE:
        *pStr = "CUDA_ERROR_INVALID_IMAGE";
        break;
    case MC_ERROR_INVALID_CONTEXT:
        *pStr = "CUDA_ERROR_INVALID_CONTEXT";
        break;
    case MC_ERROR_CONTEXT_ALREADY_CURRENT:
        *pStr = "CUDA_ERROR_CONTEXT_ALREADY_CURRENT";
        break;
    case MC_ERROR_MAP_FAILED:
        *pStr = "CUDA_ERROR_MAP_FAILED";
        break;
    case MC_ERROR_UNMAP_FAILED:
        *pStr = "CUDA_ERROR_UNMAP_FAILED";
        break;
    case MC_ERROR_ARRAY_IS_MAPPED:
        *pStr = "CUDA_ERROR_ARRAY_IS_MAPPED";
        break;
    case MC_ERROR_ALREADY_MAPPED:
        *pStr = "CUDA_ERROR_ALREADY_MAPPED";
        break;
    case MC_ERROR_NO_BINARY_FOR_GPU:
        *pStr = "CUDA_ERROR_NO_BINARY_FOR_GPU";
        break;
    case MC_ERROR_ALREADY_ACQUIRED:
        *pStr = "CUDA_ERROR_ALREADY_ACQUIRED";
        break;
    case MC_ERROR_NOT_MAPPED:
        *pStr = "CUDA_ERROR_NOT_MAPPED";
        break;
    case MC_ERROR_NOT_MAPPED_AS_ARRAY:
        *pStr = "CUDA_ERROR_NOT_MAPPED_AS_ARRAY";
        break;
    case MC_ERROR_NOT_MAPPED_AS_POINTER:
        *pStr = "CUDA_ERROR_NOT_MAPPED_AS_POINTER";
        break;
    case MC_ERROR_ECC_UNCORRECTABLE:
        *pStr = "CUDA_ERROR_ECC_UNCORRECTABLE";
        break;
    case MC_ERROR_UNSUPPORTED_LIMIT:
        *pStr = "CUDA_ERROR_UNSUPPORTED_LIMIT";
        break;
    case MC_ERROR_CONTEXT_ALREADY_IN_USE:
        *pStr = "CUDA_ERROR_CONTEXT_ALREADY_IN_USE";
        break;
    case MC_ERROR_PEER_ACCESS_UNSUPPORTED:
        *pStr = "CUDA_ERROR_PEER_ACCESS_UNSUPPORTED";
        break;
    case MC_ERROR_INVALID_KERNEL_FILE:
        *pStr = "CUDA_ERROR_INVALID_PTX";
        break;
    case MC_ERROR_INVALID_GRAPHICS_CONTEXT:
        *pStr = "CUDA_ERROR_INVALID_GRAPHICS_CONTEXT";
        break;
    case MC_ERROR_MXLINK_UNCORRECTABLE:
        *pStr = "CUDA_ERROR_NVLINK_UNCORRECTABLE";
        break;
    case MC_ERROR_JIT_COMPILER_NOT_FOUND:
        *pStr = "CUDA_ERROR_JIT_COMPILER_NOT_FOUND";
        break;
    case MC_ERROR_UNSUPPORTED_KERNEL_VERSION:
        *pStr = "CUDA_ERROR_UNSUPPORTED_PTX_VERSION";
        break;
    case MC_ERROR_JIT_COMPILATION_DISABLED:
        *pStr = "CUDA_ERROR_JIT_COMPILATION_DISABLED";
        break;
    case MC_ERROR_UNSUPPORTED_EXEC_AFFINITY:
        *pStr = "CUDA_ERROR_UNSUPPORTED_EXEC_AFFINITY";
        break;
    case MC_ERROR_INVALID_SOURCE:
        *pStr = "CUDA_ERROR_INVALID_SOURCE";
        break;
    case MC_ERROR_FILE_NOT_FOUND:
        *pStr = "CUDA_ERROR_FILE_NOT_FOUND";
        break;
    case MC_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND:
        *pStr = "CUDA_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND";
        break;
    case MC_ERROR_SHARED_OBJECT_INIT_FAILED:
        *pStr = "CUDA_ERROR_SHARED_OBJECT_INIT_FAILED";
        break;
    case MC_ERROR_OPERATING_SYSTEM:
        *pStr = "CUDA_ERROR_OPERATING_SYSTEM";
        break;
    case MC_ERROR_INVALID_HANDLE:
        *pStr = "CUDA_ERROR_INVALID_HANDLE";
        break;
    case MC_ERROR_ILLEGAL_STATE:
        *pStr = "CUDA_ERROR_ILLEGAL_STATE";
        break;
    case MC_ERROR_NOT_FOUND:
        *pStr = "CUDA_ERROR_NOT_FOUND";
        break;
    case MC_ERROR_NOT_READY:
        *pStr = "CUDA_ERROR_NOT_READY";
        break;
    case MC_ERROR_ILLEGAL_ADDRESS:
        *pStr = "CUDA_ERROR_ILLEGAL_ADDRESS";
        break;
    case MC_ERROR_LAUNCH_OUT_OF_RESOURCES:
        *pStr = "CUDA_ERROR_LAUNCH_OUT_OF_RESOURCES";
        break;
    case MC_ERROR_LAUNCH_TIMEOUT:
        *pStr = "CUDA_ERROR_LAUNCH_TIMEOUT";
        break;
    case MC_ERROR_LAUNCH_INCOMPATIBLE_TEXTURING:
        *pStr = "CUDA_ERROR_LAUNCH_INCOMPATIBLE_TEXTURING";
        break;
    case MC_ERROR_PEER_ACCESS_ALREADY_ENABLED:
        *pStr = "CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED";
        break;
    case MC_ERROR_PEER_ACCESS_NOT_ENABLED:
        *pStr = "CUDA_ERROR_PEER_ACCESS_NOT_ENABLED";
        break;
    case MC_ERROR_PRIMARY_CONTEXT_ACTIVE:
        *pStr = "CUDA_ERROR_PRIMARY_CONTEXT_ACTIVE";
        break;
    case MC_ERROR_CONTEXT_IS_DESTROYED:
        *pStr = "CUDA_ERROR_CONTEXT_IS_DESTROYED";
        break;
    case MC_ERROR_ASSERT:
        *pStr = "CUDA_ERROR_ASSERT";
        break;
    case MC_ERROR_TOO_MANY_PEERS:
        *pStr = "CUDA_ERROR_TOO_MANY_PEERS";
        break;
    case MC_ERROR_HOST_MEMORY_ALREADY_REGISTERED:
        *pStr = "CUDA_ERROR_HOST_MEMORY_ALREADY_REGISTERED";
        break;
    case MC_ERROR_HOST_MEMORY_NOT_REGISTERED:
        *pStr = "CUDA_ERROR_HOST_MEMORY_NOT_REGISTERED";
        break;
    case MC_ERROR_HARDWARE_STACK_ERROR:
        *pStr = "CUDA_ERROR_HARDWARE_STACK_ERROR";
        break;
    case MC_ERROR_ILLEGAL_INSTRUCTION:
        *pStr = "CUDA_ERROR_ILLEGAL_INSTRUCTION";
        break;
    case MC_ERROR_MISALIGNED_ADDRESS:
        *pStr = "CUDA_ERROR_MISALIGNED_ADDRESS";
        break;
    case MC_ERROR_INVALID_ADDRESS_SPACE:
        *pStr = "CUDA_ERROR_INVALID_ADDRESS_SPACE";
        break;
    case MC_ERROR_INVALID_PC:
        *pStr = "CUDA_ERROR_INVALID_PC";
        break;
    case MC_ERROR_LAUNCH_FAILED:
        *pStr = "CUDA_ERROR_LAUNCH_FAILED";
        break;
    case MC_ERROR_COOPERATIVE_LAUNCH_TOO_LARGE:
        *pStr = "CUDA_ERROR_COOPERATIVE_LAUNCH_TOO_LARGE";
        break;
    case MC_ERROR_NOT_PERMITTED:
        *pStr = "CUDA_ERROR_NOT_PERMITTED";
        break;
    case MC_ERROR_NOT_SUPPORTED:
        *pStr = "CUDA_ERROR_NOT_SUPPORTED";
        break;
    case MC_ERROR_SYSTEM_NOT_READY:
        *pStr = "CUDA_ERROR_SYSTEM_NOT_READY";
        break;
    case MC_ERROR_SYSTEM_DRIVER_MISMATCH:
        *pStr = "CUDA_ERROR_SYSTEM_DRIVER_MISMATCH";
        break;
    case MC_ERROR_COMPAT_NOT_SUPPORTED_ON_DEVICE:
        *pStr = "CUDA_ERROR_COMPAT_NOT_SUPPORTED_ON_DEVICE";
        break;
    case MC_ERROR_MPS_CONNECTION_FAILED:
        *pStr = "CUDA_ERROR_MPS_CONNECTION_FAILED";
        break;
    case MC_ERROR_MPS_RPC_FAILURE:
        *pStr = "CUDA_ERROR_MPS_RPC_FAILURE";
        break;
    case MC_ERROR_MPS_SERVER_NOT_READY:
        *pStr = "CUDA_ERROR_MPS_SERVER_NOT_READY";
        break;
    case MC_ERROR_MPS_MAX_CLIENTS_REACHED:
        *pStr = "CUDA_ERROR_MPS_MAX_CLIENTS_REACHED";
        break;
    case MC_ERROR_MPS_MAX_CONNECTIONS_REACHED:
        *pStr = "CUDA_ERROR_MPS_MAX_CONNECTIONS_REACHED";
        break;
    case MC_ERROR_STREAM_CAPTURE_UNSUPPORTED:
        *pStr = "CUDA_ERROR_STREAM_CAPTURE_UNSUPPORTED";
        break;
    case MC_ERROR_STREAM_CAPTURE_INVALIDATED:
        *pStr = "CUDA_ERROR_STREAM_CAPTURE_INVALIDATED";
        break;
    case MC_ERROR_STREAM_CAPTURE_MERGE:
        *pStr = "CUDA_ERROR_STREAM_CAPTURE_MERGE";
        break;
    case MC_ERROR_STREAM_CAPTURE_UNMATCHED:
        *pStr = "CUDA_ERROR_STREAM_CAPTURE_UNMATCHED";
        break;
    case MC_ERROR_STREAM_CAPTURE_UNJOINED:
        *pStr = "CUDA_ERROR_STREAM_CAPTURE_UNJOINED";
        break;
    case MC_ERROR_STREAM_CAPTURE_ISOLATION:
        *pStr = "CUDA_ERROR_STREAM_CAPTURE_ISOLATION";
        break;
    case MC_ERROR_STREAM_CAPTURE_IMPLICIT:
        *pStr = "CUDA_ERROR_STREAM_CAPTURE_IMPLICIT";
        break;
    case MC_ERROR_CAPTURED_EVENT:
        *pStr = "CUDA_ERROR_CAPTURED_EVENT";
        break;
    case MC_ERROR_STREAM_CAPTURE_WRONG_THREAD:
        *pStr = "CUDA_ERROR_STREAM_CAPTURE_WRONG_THREAD";
        break;
    case MC_ERROR_TIMEOUT:
        *pStr = "CUDA_ERROR_TIMEOUT";
        break;
    case MC_ERROR_GRAPH_EXEC_UPDATE_FAILURE:
        *pStr = "CUDA_ERROR_GRAPH_EXEC_UPDATE_FAILURE";
        break;
    case MC_ERROR_EXTERNAL_DEVICE:
        *pStr = "CUDA_ERROR_EXTERNAL_DEVICE";
        break;
    case MC_ERROR_UNKNOWN:
        *pStr = "CUDA_ERROR_UNKNOWN";
        break;
    default:
        *pStr = nullptr;
        return MC_ERROR_INVALID_VALUE;
    }
    return MC_SUCCESS;
}

mcDrvError_t wcuGetErrorString(mcDrvError_t error, const char **pStr)
{
    switch (error) {
    case MC_SUCCESS:
        *pStr = "no error";
        break;
    case MC_ERROR_INVALID_VALUE:
        *pStr = "invalid argument";
        break;
    case MC_ERROR_OUT_OF_MEMORY:
        *pStr = "out of memory";
        break;
    case MC_ERROR_NOT_INITIALIZED:
        *pStr = "initialization error";
        break;
    case MC_ERROR_DEINITIALIZED:
        *pStr = "driver shutting down";
        break;
    case MC_ERROR_PROFILER_DISABLED:
        *pStr = "profiler disabled while using external "
                "profiling tool";
        break;
    case MC_ERROR_PROFILER_NOT_INITIALIZED:
        *pStr = "profiler not initialized: call "
                "cudaProfilerInitialize()";
        break;
    case MC_ERROR_PROFILER_ALREADY_STARTED:
        *pStr = "profiler already started";
        break;
    case MC_ERROR_PROFILER_ALREADY_STOPPED:
        *pStr = "profiler already stopped";
        break;
    case MC_ERROR_STUB_LIBRARY:
        *pStr = "CUDA driver is a stub library";
        break;
    case MC_ERROR_NO_DEVICE:
        *pStr = "no CUDA-capable device is detected";
        break;
    case MC_ERROR_INVALID_DEVICE:
        *pStr = "invalid device ordinal";
        break;
    case MC_ERROR_DEVICE_NOT_LICENSED:
        *pStr = "device doesn't have valid Grid license";
        break;
    case MC_ERROR_INVALID_IMAGE:
        *pStr = "device kernel image is invalid";
        break;
    case MC_ERROR_INVALID_CONTEXT:
        *pStr = "invalid device context";
        break;
    case MC_ERROR_CONTEXT_ALREADY_CURRENT:
        *pStr = "context already current";
        break;
    case MC_ERROR_MAP_FAILED:
        *pStr = "mapping of buffer object failed";
        break;
    case MC_ERROR_UNMAP_FAILED:
        *pStr = "unmapping of buffer object failed";
        break;
    case MC_ERROR_ARRAY_IS_MAPPED:
        *pStr = "array is mapped";
        break;
    case MC_ERROR_ALREADY_MAPPED:
        *pStr = "resource already mapped";
        break;
    case MC_ERROR_NO_BINARY_FOR_GPU:
        *pStr = "no kernel image is available for execution on "
                "the device";
        break;
    case MC_ERROR_ALREADY_ACQUIRED:
        *pStr = "resource already acquired";
        break;
    case MC_ERROR_NOT_MAPPED:
        *pStr = "resource not mapped";
        break;
    case MC_ERROR_NOT_MAPPED_AS_ARRAY:
        *pStr = "resource not mapped as array";
        break;
    case MC_ERROR_NOT_MAPPED_AS_POINTER:
        *pStr = "resource not mapped as pointer";
        break;
    case MC_ERROR_ECC_UNCORRECTABLE:
        *pStr = "uncorrectable ECC error encountered";
        break;
    case MC_ERROR_UNSUPPORTED_LIMIT:
        *pStr = "limit is not supported on this architecture";
        break;
    case MC_ERROR_CONTEXT_ALREADY_IN_USE:
        *pStr = "exclusive-thread device already in use by a "
                "different thread";
        break;
    case MC_ERROR_PEER_ACCESS_UNSUPPORTED:
        *pStr = "peer access is not supported between these two "
                "devices";
        break;
    case MC_ERROR_INVALID_KERNEL_FILE:
        *pStr = "a PTX JIT compilation failed";
        break;
    case MC_ERROR_INVALID_GRAPHICS_CONTEXT:
        *pStr = "invalid OpenGL or DirectX context";
        break;
    case MC_ERROR_MXLINK_UNCORRECTABLE:
        *pStr = "uncorrectable NVLink error detected during the "
                "execution";
        break;
    case MC_ERROR_JIT_COMPILER_NOT_FOUND:
        *pStr = "PTX JIT compiler library not found";
        break;
    case MC_ERROR_UNSUPPORTED_KERNEL_VERSION:
        *pStr = "the provided PTX was compiled with an "
                "unsupported toolchain.";
        break;
    case MC_ERROR_JIT_COMPILATION_DISABLED:
        *pStr = "PTX JIT compilation was disabled";
        break;
    case MC_ERROR_UNSUPPORTED_EXEC_AFFINITY:
        *pStr = "the provided execution affinity is not "
                "supported";
        break;
    case MC_ERROR_INVALID_SOURCE:
        *pStr = "device kernel image is invalid";
        break;
    case MC_ERROR_FILE_NOT_FOUND:
        *pStr = "file not found";
        break;
    case MC_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND:
        *pStr = "shared object symbol not found";
        break;
    case MC_ERROR_SHARED_OBJECT_INIT_FAILED:
        *pStr = "shared object initialization failed";
        break;
    case MC_ERROR_OPERATING_SYSTEM:
        *pStr = "OS call failed or operation not supported on "
                "this OS";
        break;
    case MC_ERROR_INVALID_HANDLE:
        *pStr = "invalid resource handle";
        break;
    case MC_ERROR_ILLEGAL_STATE:
        *pStr = "the operation cannot be performed in the "
                "present state";
        break;
    case MC_ERROR_NOT_FOUND:
        *pStr = "named symbol not found";
        break;
    case MC_ERROR_NOT_READY:
        *pStr = "device not ready";
        break;
    case MC_ERROR_ILLEGAL_ADDRESS:
        *pStr = "an illegal memory access was encountered";
        break;
    case MC_ERROR_LAUNCH_OUT_OF_RESOURCES:
        *pStr = "too many resources requested for launch";
        break;
    case MC_ERROR_LAUNCH_TIMEOUT:
        *pStr = "the launch timed out and was terminated";
        break;
    case MC_ERROR_LAUNCH_INCOMPATIBLE_TEXTURING:
        *pStr = "launch uses incompatible texturing mode";
        break;
    case MC_ERROR_PEER_ACCESS_ALREADY_ENABLED:
        *pStr = "peer access is already enabled";
        break;
    case MC_ERROR_PEER_ACCESS_NOT_ENABLED:
        *pStr = "peer access has not been enabled";
        break;
    case MC_ERROR_PRIMARY_CONTEXT_ACTIVE:
        *pStr = "cannot set while device is active in this "
                "process";
        break;
    case MC_ERROR_CONTEXT_IS_DESTROYED:
        *pStr = "context is destroyed";
        break;
    case MC_ERROR_ASSERT:
        *pStr = "device-side assert triggered";
        break;
    case MC_ERROR_TOO_MANY_PEERS:
        *pStr = "peer mapping resources exhausted";
        break;
    case MC_ERROR_HOST_MEMORY_ALREADY_REGISTERED:
        *pStr = "part or all of the requested memory range is "
                "already mapped";
        break;
    case MC_ERROR_HOST_MEMORY_NOT_REGISTERED:
        *pStr = "pointer does not correspond to a registered "
                "memory region";
        break;
    case MC_ERROR_HARDWARE_STACK_ERROR:
        *pStr = "hardware stack error";
        break;
    case MC_ERROR_ILLEGAL_INSTRUCTION:
        *pStr = "an illegal instruction was encountered";
        break;
    case MC_ERROR_MISALIGNED_ADDRESS:
        *pStr = "misaligned address";
        break;
    case MC_ERROR_INVALID_ADDRESS_SPACE:
        *pStr = "operation not supported on global/shared "
                "address space";
        break;
    case MC_ERROR_INVALID_PC:
        *pStr = "invalid program counter";
        break;
    case MC_ERROR_LAUNCH_FAILED:
        *pStr = "unspecified launch failure";
        break;
    case MC_ERROR_COOPERATIVE_LAUNCH_TOO_LARGE:
        *pStr = "too many blocks in cooperative launch";
        break;
    case MC_ERROR_NOT_PERMITTED:
        *pStr = "operation not permitted";
        break;
    case MC_ERROR_NOT_SUPPORTED:
        *pStr = "operation not supported";
        break;
    case MC_ERROR_SYSTEM_NOT_READY:
        *pStr = "system not yet initialized";
        break;
    case MC_ERROR_SYSTEM_DRIVER_MISMATCH:
        *pStr = "system has unsupported display driver / cuda "
                "driver combination";
        break;
    case MC_ERROR_COMPAT_NOT_SUPPORTED_ON_DEVICE:
        *pStr = "forward compatibility was attempted on non "
                "supported HW";
        break;
    case MC_ERROR_MPS_CONNECTION_FAILED:
        *pStr = "MPS client failed to connect to the MPS "
                "control daemon or the "
                "MPS server";
        break;
    case MC_ERROR_MPS_RPC_FAILURE:
        *pStr = "the remote procedural call between the MPS "
                "server and the MPS "
                "client failed";
        break;
    case MC_ERROR_MPS_SERVER_NOT_READY:
        *pStr = "MPS server is not ready to accept new MPS "
                "client requests";
        break;
    case MC_ERROR_MPS_MAX_CLIENTS_REACHED:
        *pStr = "the hardware resources required to create MPS "
                "client have been "
                "exhausted";
        break;
    case MC_ERROR_MPS_MAX_CONNECTIONS_REACHED:
        *pStr = "the hardware resources required to support "
                "device connections "
                "have been exhausted";
        break;
    case MC_ERROR_STREAM_CAPTURE_UNSUPPORTED:
        *pStr = "operation not permitted when stream is "
                "capturing";
        break;
    case MC_ERROR_STREAM_CAPTURE_INVALIDATED:
        *pStr = "operation failed due to a previous error "
                "during capture";
        break;
    case MC_ERROR_STREAM_CAPTURE_MERGE:
        *pStr = "operation would result in a merge of separate "
                "capture sequences";
        break;
    case MC_ERROR_STREAM_CAPTURE_UNMATCHED:
        *pStr = "capture was not ended in the same stream as it "
                "began";
        break;
    case MC_ERROR_STREAM_CAPTURE_UNJOINED:
        *pStr = "capturing stream has unjoined work";
        break;
    case MC_ERROR_STREAM_CAPTURE_ISOLATION:
        *pStr = "dependency created on uncaptured work in "
                "another stream";
        break;
    case MC_ERROR_STREAM_CAPTURE_IMPLICIT:
        *pStr = "operation would make the legacy stream depend "
                "on a capturing "
                "blocking stream";
        break;
    case MC_ERROR_CAPTURED_EVENT:
        *pStr = "operation not permitted on an event last "
                "recorded in a capturing "
                "stream";
        break;
    case MC_ERROR_STREAM_CAPTURE_WRONG_THREAD:
        *pStr = "attempt to terminate a thread-local capture "
                "sequence from "
                "another thread";
        break;
    case MC_ERROR_TIMEOUT:
        *pStr = "wait operation timed out";
        break;
    case MC_ERROR_GRAPH_EXEC_UPDATE_FAILURE:
        *pStr = "the graph update was not performed because it "
                "included changes "
                "which violated constraints specific to "
                "instantiated graph update";
        break;
    case MC_ERROR_EXTERNAL_DEVICE:
        *pStr = "an async error has occured in external entity "
                "outside of CUDA";
        break;
    case MC_ERROR_UNKNOWN:
        *pStr = "unknown error";
        break;
    default:
        *pStr = nullptr;
        return MC_ERROR_INVALID_VALUE;
    }
    return MC_SUCCESS;
}

size_t getElementSize(const mcArray_const_t array)
{
    switch (array->Format) {
    case MC_AD_FORMAT_UNSIGNED_INT8:
    case MC_AD_FORMAT_SIGNED_INT8:
        return 1 * array->NumChannels;
    case MC_AD_FORMAT_UNSIGNED_INT16:
    case MC_AD_FORMAT_SIGNED_INT16:
    case MC_AD_FORMAT_HALF:
        return 2 * array->NumChannels;
    case MC_AD_FORMAT_UNSIGNED_INT32:
    case MC_AD_FORMAT_SIGNED_INT32:
    case MC_AD_FORMAT_FLOAT:
        return 4 * array->NumChannels;
    }

    return 0;
}

std::pair<mcMemoryType, mcMemoryType> getMemoryType(const mcMemcpyKind kind)
{
    switch (kind) {
    case mcMemcpyHostToHost:
        return {mcMemoryTypeHost, mcMemoryTypeHost};
    case mcMemcpyHostToDevice:
        return {mcMemoryTypeHost, mcMemoryTypeDevice};
    case mcMemcpyDeviceToHost:
        return {mcMemoryTypeDevice, mcMemoryTypeHost};
    case mcMemcpyDeviceToDevice:
        return {mcMemoryTypeDevice, mcMemoryTypeDevice};
    case mcMemcpyDefault:
        return {mcMemoryTypeUnified, mcMemoryTypeUnified};
    }

    return {};
}

MACA_MEMCPY3D getMACAMemcpy3DDesc(const struct mcMemcpy3DParms &desc)
{
    MACA_MEMCPY3D descDrv = {};

    descDrv.WidthInBytes = desc.extent.width;
    descDrv.Height       = desc.extent.height;
    descDrv.Depth        = desc.extent.depth;

    descDrv.srcXInBytes = desc.srcPos.x;
    descDrv.srcY        = desc.srcPos.y;
    descDrv.srcZ        = desc.srcPos.z;
    descDrv.srcLOD      = 0;

    descDrv.dstXInBytes = desc.dstPos.x;
    descDrv.dstY        = desc.dstPos.y;
    descDrv.dstZ        = desc.dstPos.z;
    descDrv.dstLOD      = 0;

    if (desc.srcArray != nullptr) {
        descDrv.srcMemoryType = mcMemoryTypeArray;
        descDrv.srcArray      = reinterpret_cast<MCarray>(desc.srcArray);
        descDrv.srcXInBytes *= getElementSize(desc.srcArray);
    }

    if (desc.srcPtr.ptr != nullptr) {
        descDrv.srcMemoryType = std::get<0>(getMemoryType(desc.kind));
        if (descDrv.srcMemoryType == mcMemoryTypeDevice) {
            descDrv.srcDevice = reinterpret_cast<MCdeviceptr>(desc.srcPtr.ptr);
        } else if (descDrv.srcMemoryType == mcMemoryTypeHost) {
            descDrv.srcHost = desc.srcPtr.ptr;
        } else if (descDrv.srcMemoryType == mcMemoryTypeUnregistered) {
            // LogError("Unprocessed memory type mcMemoryTypeUnregistered");
        } else if (descDrv.srcMemoryType == mcMemoryTypeUnified) {
            descDrv.srcDevice = reinterpret_cast<MCdeviceptr>(desc.srcPtr.ptr);
            descDrv.srcHost   = desc.srcPtr.ptr;
        } else {
            // LogPrintfError("Unknown memory type: %d\n", descDrv.dstMemoryType);
        }
        descDrv.srcPitch  = desc.srcPtr.pitch;
        descDrv.srcHeight = desc.srcPtr.ysize;
    }

    if (desc.dstArray != nullptr) {
        descDrv.dstMemoryType = mcMemoryTypeArray;
        descDrv.dstArray      = reinterpret_cast<MCarray>(desc.dstArray);
        descDrv.dstXInBytes *= getElementSize(desc.dstArray);
    }

    if (desc.dstPtr.ptr != nullptr) {
        descDrv.dstMemoryType = std::get<1>(getMemoryType(desc.kind));
        if (descDrv.dstMemoryType == mcMemoryTypeDevice) {
            descDrv.dstDevice = reinterpret_cast<MCdeviceptr>(desc.dstPtr.ptr);
        } else if (descDrv.dstMemoryType == mcMemoryTypeHost) {
            descDrv.dstHost = desc.dstPtr.ptr;
        } else if (descDrv.dstMemoryType == mcMemoryTypeUnregistered) {
            // LogError("Unprocessed memory type mcMemoryTypeUnregistered");
        } else if (descDrv.dstMemoryType == mcMemoryTypeUnified) {
            descDrv.dstDevice = reinterpret_cast<MCdeviceptr>(desc.dstPtr.ptr);
            descDrv.dstHost   = desc.dstPtr.ptr;
        } else {
            // LogPrintfError("Unknown memory type: %d\n", descDrv.dstMemoryType);
        }
        descDrv.dstPitch  = desc.dstPtr.pitch;
        descDrv.dstHeight = desc.dstPtr.ysize;
    }

    if ((desc.srcArray != nullptr) && (desc.dstArray == nullptr)) {
        descDrv.WidthInBytes *= getElementSize(desc.srcArray);
    } else if ((desc.srcArray == nullptr) && (desc.dstArray != nullptr)) {
        descDrv.WidthInBytes *= getElementSize(desc.dstArray);
    } else if ((desc.srcArray != nullptr) && (desc.dstArray != nullptr)) {
        descDrv.WidthInBytes *= getElementSize(desc.dstArray);
    }

    return descDrv;
}

inline mcChannelFormatDesc getChannelFormatDesc(int numChannels, mcArray_Format arrayFormat)
{
    switch (arrayFormat) {
    case MC_AD_FORMAT_UNSIGNED_INT8:
        switch (numChannels) {
        case 1:
            return {8, 0, 0, 0, mcChannelFormatKindUnsigned};
        case 2:
            return {8, 8, 0, 0, mcChannelFormatKindUnsigned};
        case 4:
            return {8, 8, 8, 8, mcChannelFormatKindUnsigned};
        }
    case MC_AD_FORMAT_SIGNED_INT8:
        switch (numChannels) {
        case 1:
            return {8, 0, 0, 0, mcChannelFormatKindSigned};
        case 2:
            return {8, 8, 0, 0, mcChannelFormatKindSigned};
        case 4:
            return {8, 8, 8, 8, mcChannelFormatKindSigned};
        }
    case MC_AD_FORMAT_UNSIGNED_INT16:
        switch (numChannels) {
        case 1:
            return {16, 0, 0, 0, mcChannelFormatKindUnsigned};
        case 2:
            return {16, 16, 0, 0, mcChannelFormatKindUnsigned};
        case 4:
            return {16, 16, 16, 16, mcChannelFormatKindUnsigned};
        }
    case MC_AD_FORMAT_SIGNED_INT16:
        switch (numChannels) {
        case 1:
            return {16, 0, 0, 0, mcChannelFormatKindSigned};
        case 2:
            return {16, 16, 0, 0, mcChannelFormatKindSigned};
        case 4:
            return {16, 16, 16, 16, mcChannelFormatKindSigned};
        }
    case MC_AD_FORMAT_UNSIGNED_INT32:
        switch (numChannels) {
        case 1:
            return {32, 0, 0, 0, mcChannelFormatKindUnsigned};
        case 2:
            return {32, 32, 0, 0, mcChannelFormatKindUnsigned};
        case 4:
            return {32, 32, 32, 32, mcChannelFormatKindUnsigned};
        }
    case MC_AD_FORMAT_SIGNED_INT32:
        switch (numChannels) {
        case 1:
            return {32, 0, 0, 0, mcChannelFormatKindSigned};
        case 2:
            return {32, 32, 0, 0, mcChannelFormatKindSigned};
        case 4:
            return {32, 32, 32, 32, mcChannelFormatKindSigned};
        }
    case MC_AD_FORMAT_HALF:
        switch (numChannels) {
        case 1:
            return {16, 0, 0, 0, mcChannelFormatKindFloat};
        case 2:
            return {16, 16, 0, 0, mcChannelFormatKindFloat};
        case 4:
            return {16, 16, 16, 16, mcChannelFormatKindFloat};
        }
    case MC_AD_FORMAT_FLOAT:
        switch (numChannels) {
        case 1:
            return {32, 0, 0, 0, mcChannelFormatKindFloat};
        case 2:
            return {32, 32, 0, 0, mcChannelFormatKindFloat};
        case 4:
            return {32, 32, 32, 32, mcChannelFormatKindFloat};
        }
    }

    return {};
}

inline unsigned int getNumChannels(const mcChannelFormatDesc &desc)
{
    return ((desc.x != 0) + (desc.y != 0) + (desc.z != 0) + (desc.w != 0));
}

inline mcArray_Format getArrayFormat(const mcChannelFormatDesc &desc)
{
    switch (desc.f) {
    case mcChannelFormatKindUnsigned:
        switch (desc.x) {
        case 8:
            return MC_AD_FORMAT_UNSIGNED_INT8;
        case 16:
            return MC_AD_FORMAT_UNSIGNED_INT16;
        case 32:
            return MC_AD_FORMAT_UNSIGNED_INT32;
        }
    case mcChannelFormatKindSigned:
        switch (desc.x) {
        case 8:
            return MC_AD_FORMAT_SIGNED_INT8;
        case 16:
            return MC_AD_FORMAT_SIGNED_INT16;
        case 32:
            return MC_AD_FORMAT_SIGNED_INT32;
        }
    case mcChannelFormatKindFloat:
        switch (desc.x) {
        case 16:
            return MC_AD_FORMAT_HALF;
        case 32:
            return MC_AD_FORMAT_FLOAT;
        }
    default:
        break;
    }

    return {};
}

inline mcTextureReadMode getReadMode(const unsigned int flags)
{
    if (flags & MC_TRSF_READ_AS_INTEGER) {
        return mcReadModeElementType;
    } else {
        return mcReadModeNormalizedFloat;
    }
}

inline unsigned int getReadMode(const mcTextureReadMode mode)
{
    if (mode == mcReadModeElementType) {
        return MC_TRSF_READ_AS_INTEGER;
    } else {
        return 0;
    }
}

inline int getsRGB(const unsigned int flags)
{
    if (flags & MC_TRSF_SRGB) {
        return 1;
    } else {
        return 0;
    }
}

inline unsigned int getsRGB(const int sRGB)
{
    if (sRGB == 1) {
        return MC_TRSF_SRGB;
    } else {
        return 0;
    }
}

inline int getNormalizedCoords(const unsigned int flags)
{
    if (flags & MC_TRSF_NORMALIZED_COORDINATES) {
        return 1;
    } else {
        return 0;
    }
}

inline unsigned int getNormalizedCoords(const int normalizedCoords)
{
    if (normalizedCoords == 1) {
        return MC_TRSF_NORMALIZED_COORDINATES;
    } else {
        return 0;
    }
}

inline mcResourceDesc getResourceDesc(const mcDrvResourceDesc &resDesc)
{
    mcResourceDesc desc;

    desc.resType = static_cast<mcResourceType>(resDesc.resType);

    switch (desc.resType) {
    case mcResourceTypeArray:
        desc.res.array.array = reinterpret_cast<mcArray_t>(resDesc.res.array.hArray);
        break;
    case mcResourceTypeMipmappedArray:
        desc.res.mipmap.mipmap = resDesc.res.mipmap.hMipmappedArray;
        break;
    case mcResourceTypeLinear:
        desc.res.linear.devPtr = reinterpret_cast<void *>(resDesc.res.linear.devPtr);
        desc.res.linear.desc =
            getChannelFormatDesc(resDesc.res.linear.numChannels, resDesc.res.linear.format);
        desc.res.linear.sizeInBytes = resDesc.res.linear.sizeInBytes;
        break;
    case mcResourceTypePitch2D:
        desc.res.pitch2D.devPtr = reinterpret_cast<void *>(resDesc.res.pitch2D.devPtr);
        desc.res.pitch2D.desc =
            getChannelFormatDesc(resDesc.res.pitch2D.numChannels, resDesc.res.pitch2D.format);
        desc.res.pitch2D.width        = resDesc.res.pitch2D.width;
        desc.res.pitch2D.height       = resDesc.res.pitch2D.height;
        desc.res.pitch2D.pitchInBytes = resDesc.res.pitch2D.pitchInBytes;
        break;
    default:
        break;
    }

    return desc;
}

inline mcDrvResourceDesc getResourceDesc(const mcResourceDesc &resDesc)
{
    mcDrvResourceDesc desc;

    desc.resType = static_cast<mcDrvResourcetype>(resDesc.resType);
    switch (desc.resType) {
    case MC_RESOURCE_TYPE_ARRAY:
        desc.res.array.hArray = reinterpret_cast<MCarray>(resDesc.res.array.array);
        break;
    case MC_RESOURCE_TYPE_MIPMAPPED_ARRAY:
        desc.res.mipmap.hMipmappedArray = resDesc.res.mipmap.mipmap;
        break;
    case MC_RESOURCE_TYPE_LINEAR:
        desc.res.linear.devPtr      = reinterpret_cast<mcDrvDeviceptr_t>(resDesc.res.linear.devPtr);
        desc.res.linear.numChannels = getNumChannels(resDesc.res.linear.desc);
        desc.res.linear.format      = getArrayFormat(resDesc.res.linear.desc);
        desc.res.linear.sizeInBytes = resDesc.res.linear.sizeInBytes;
        break;
    case MC_RESOURCE_TYPE_PITCH2D:
        desc.res.pitch2D.devPtr = reinterpret_cast<mcDrvDeviceptr_t>(resDesc.res.pitch2D.devPtr);
        desc.res.pitch2D.numChannels  = getNumChannels(resDesc.res.pitch2D.desc);
        desc.res.pitch2D.format       = getArrayFormat(resDesc.res.pitch2D.desc);
        desc.res.pitch2D.width        = resDesc.res.pitch2D.width;
        desc.res.pitch2D.height       = resDesc.res.pitch2D.height;
        desc.res.pitch2D.pitchInBytes = resDesc.res.pitch2D.pitchInBytes;
        break;
    default:
        break;
    }

    return desc;
}

inline mcTextureDesc getTextureDesc(const mcDrvTextureDesc &texDesc)
{
    mcTextureDesc desc;

    desc.addressMode[0]   = static_cast<mcTextureAddressMode>(texDesc.addressMode[0]);
    desc.addressMode[1]   = static_cast<mcTextureAddressMode>(texDesc.addressMode[1]);
    desc.addressMode[2]   = static_cast<mcTextureAddressMode>(texDesc.addressMode[2]);
    desc.filterMode       = static_cast<mcTextureFilterMode>(texDesc.filterMode);
    desc.sRGB             = getsRGB(texDesc.flags);
    desc.normalizedCoords = getNormalizedCoords(texDesc.flags);
    desc.readMode         = getReadMode(texDesc.flags);
    std::memcpy(desc.borderColor, texDesc.borderColor, sizeof(desc.borderColor));
    desc.maxAnisotropy       = texDesc.maxAnisotropy;
    desc.mipmapFilterMode    = static_cast<mcTextureFilterMode>(texDesc.mipmapFilterMode);
    desc.mipmapLevelBias     = texDesc.mipmapLevelBias;
    desc.minMipmapLevelClamp = texDesc.minMipmapLevelClamp;
    desc.maxMipmapLevelClamp = texDesc.maxMipmapLevelClamp;

    return desc;
}

inline mcDrvTextureDesc getTextureDesc(const mcTextureDesc &texDesc)
{
    mcDrvTextureDesc desc;

    desc.addressMode[0] = static_cast<mcDrvAddress_mode>(texDesc.addressMode[0]);
    desc.addressMode[1] = static_cast<mcDrvAddress_mode>(texDesc.addressMode[1]);
    desc.addressMode[2] = static_cast<mcDrvAddress_mode>(texDesc.addressMode[2]);
    desc.filterMode     = static_cast<mcDrvFilter_mode>(texDesc.filterMode);
    desc.flags          = 0;
    desc.flags |= getReadMode(texDesc.readMode);
    desc.flags |= getsRGB(texDesc.sRGB);
    desc.flags |= getNormalizedCoords(texDesc.normalizedCoords);
    desc.maxAnisotropy       = texDesc.maxAnisotropy;
    desc.mipmapFilterMode    = static_cast<mcDrvFilter_mode>(texDesc.mipmapFilterMode);
    desc.mipmapLevelBias     = texDesc.mipmapLevelBias;
    desc.minMipmapLevelClamp = texDesc.minMipmapLevelClamp;
    desc.maxMipmapLevelClamp = texDesc.maxMipmapLevelClamp;
    std::memcpy(desc.borderColor, texDesc.borderColor, sizeof(desc.borderColor));

    return desc;
}

inline mcResourceViewDesc getResourceViewDesc(const mcDrvResourceViewDesc &resViewDesc)
{
    mcResourceViewDesc desc;

    desc.format           = static_cast<mcResourceViewFormat>(resViewDesc.format);
    desc.width            = resViewDesc.width;
    desc.height           = resViewDesc.height;
    desc.depth            = resViewDesc.depth;
    desc.firstMipmapLevel = resViewDesc.firstMipmapLevel;
    desc.lastMipmapLevel  = resViewDesc.lastMipmapLevel;
    desc.firstLayer       = resViewDesc.firstLayer;
    desc.lastLayer        = resViewDesc.lastLayer;

    return desc;
}

inline mcDrvResourceViewDesc getResourceViewDesc(const mcResourceViewDesc &resViewDesc)
{
    mcDrvResourceViewDesc desc;

    desc.format           = static_cast<mcDrvResourceViewFormat>(resViewDesc.format);
    desc.width            = resViewDesc.width;
    desc.height           = resViewDesc.height;
    desc.depth            = resViewDesc.depth;
    desc.firstMipmapLevel = resViewDesc.firstMipmapLevel;
    desc.lastMipmapLevel  = resViewDesc.lastMipmapLevel;
    desc.firstLayer       = resViewDesc.firstLayer;
    desc.lastLayer        = resViewDesc.lastLayer;

    return desc;
}

//---------------------------------------------------------------------------//
// Initialization
//---------------------------------------------------------------------------//
mcDrvError_t wcuInit(unsigned int flags) { return mcErrorTomcDrvError(mcInit(flags)); }

//---------------------------------------------------------------------------//
// Version Version Management
//---------------------------------------------------------------------------//
mcDrvError_t __attribute__((weak)) wcuDriverGetVersion(int *driverVersion)
{
    if (driverVersion == (void *)0) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }
    if (__wcuda_version_internal__ < 1000) {
        return mcErrorTomcDrvError(mcErrorNotSupported);
    } else {
        *driverVersion = __wcuda_version_internal__;
    }
    return MC_SUCCESS;
}

//---------------------------------------------------------------------------//
// Device Management
//---------------------------------------------------------------------------//

mcDrvError_t wcuDeviceGetAttribute(int *pi, mcDrvDeviceAttribute_t drv_attr, mcDrvDevice_t device)
{
    enum mcDeviceAttribute_t attr = (enum mcDeviceAttribute_t)(drv_attr);

    if (pi == nullptr) {
        return MC_ERROR_INVALID_VALUE;
    }
    if ((attr < mcDeviceAttributeMaxThreadsPerBlock) || (attr >= mcDeviceAttributeUnknow)) {
        return MC_ERROR_INVALID_VALUE;
    }
    int count = 0;
    wcuDeviceGetCount(&count);
    if (device < 0 || device >= count) {
        return MC_ERROR_INVALID_DEVICE;
    }

    mcDeviceProp_t dev_prop = {};
    mcDeviceProp_t *prop    = &dev_prop;
    auto ret                = mcGetDeviceProperties(prop, device);
    if (ret != mcSuccess) {
        return mcErrorTomcDrvError(ret);
    }
    if (__NV_ARCH_V100 == __nv_arch_type_internal__) {
        prop->major = 7;
        prop->minor = 0;
    } else if (__NV_ARCH_T4 == __nv_arch_type_internal__) {
        prop->major = 7;
        prop->minor = 5;
    } else if (__NV_ARCH_A100 == __nv_arch_type_internal__) {
        prop->major = 8;
        prop->minor = 0;
    }

    char *var            = getenv("WARPSIZE");
    prop->warpSize       = (var != nullptr) ? atoi(var) : prop->warpSize;
    prop->waveSize       = prop->warpSize;
    var                  = getenv("TOTALMEMORY");
    prop->totalGlobalMem = (var != nullptr) ? (size_t)strtoul(var, 0, 0) : prop->totalGlobalMem;

    switch (attr) {
    case mcDeviceAttributeMaxThreadsPerBlock:
        *pi = dev_prop.maxThreadsPerBlock;
        break;
    case mcDeviceAttributeMaxBlockDimX:
        *pi = dev_prop.maxThreadsDim[0];
        break;
    case mcDeviceAttributeMaxBlockDimY:
        *pi = dev_prop.maxThreadsDim[1];
        break;
    case mcDeviceAttributeMaxBlockDimZ:
        *pi = dev_prop.maxThreadsDim[2];
        break;
    case mcDeviceAttributeMaxGridDimX:
        *pi = dev_prop.maxGridSize[0];
        break;
    case mcDeviceAttributeMaxGridDimY:
        *pi = dev_prop.maxGridSize[1];
        break;
    case mcDeviceAttributeMaxGridDimZ:
        *pi = dev_prop.maxGridSize[2];
        break;
    case mcDeviceAttributeMaxSharedMemoryPerBlock:
        *pi = dev_prop.sharedMemPerBlock;
        break;
    case mcDeviceAttributeTotalConstantMemory:
        *pi = dev_prop.totalConstMem;
        break;
    case mcDeviceAttributeWarpSize:
    case mcDeviceAttributeWaveSize:
        *pi = dev_prop.warpSize;
        break;
    case mcDeviceAttributeMaxRegistersPerBlock:
        *pi = dev_prop.regsPerBlock;
        break;
    case mcDeviceAttributeMaxRegistersPerMultiprocessor:
        *pi = dev_prop.regsPerMultiprocessor;
        break;
    case mcDeviceAttributeClockRate:
        *pi = dev_prop.clockRate;
        break;
    case mcDeviceAttributeMemoryClockRate:
        *pi = dev_prop.memoryClockRate;
        break;
    case mcDeviceAttributeMemoryBusWidth:
        *pi = dev_prop.memoryBusWidth;
        break;
    case mcDeviceAttributeMultiProcessorCount:
        *pi = dev_prop.multiProcessorCount;
        break;
    case mcDeviceAttributeComputeMode:
        *pi = dev_prop.computeMode;
        break;
    case mcDeviceAttributeL2CacheSize:
        *pi = dev_prop.l2CacheSize;
        break;
    case mcDeviceAttributeMaxThreadsPerMultiProcessor:
        *pi = dev_prop.maxThreadsPerMultiProcessor;
        break;
    case mcDeviceAttributeComputeCapabilityMajor:
        *pi = dev_prop.major;
        break;
    case mcDeviceAttributeComputeCapabilityMinor:
        *pi = dev_prop.minor;
        break;
    case mcDeviceAttributePciBusId:
        *pi = dev_prop.pciBusID;
        break;
    case mcDeviceAttributeConcurrentKernels:
        *pi = dev_prop.concurrentKernels;
        break;
    case mcDeviceAttributePciDeviceId:
        *pi = dev_prop.pciDeviceID;
        break;
    case mcDeviceAttributeMaxSharedMemoryPerMultiprocessor:
    case mcDeviceAttributeMaxSharedMemoryPerBlockOptin:
        *pi = dev_prop.maxSharedMemoryPerMultiProcessor;
        break;
    case mcDeviceAttributeIsMultiGpuBoard:
        *pi = dev_prop.isMultiGpuBoard;
        break;
    case mcDeviceAttributeCooperativeLaunch:
        *pi = dev_prop.cooperativeLaunch;
        break;
    case mcDeviceAttributeCooperativeMultiDeviceLaunch:
        *pi = dev_prop.cooperativeMultiDeviceLaunch;
        break;
    case mcDeviceAttributeIntegrated:
        *pi = dev_prop.integrated;
        break;
    case mcDeviceAttributeMaxTexture1DWidth:
        *pi = dev_prop.maxTexture1D;
        break;
    case mcDeviceAttributeMaxTexture2DWidth:
        *pi = dev_prop.maxTexture2D[0];
        break;
    case mcDeviceAttributeMaxTexture2DHeight:
        *pi = dev_prop.maxTexture2D[1];
        break;
    case mcDeviceAttributeMaxTexture3DWidth:
        *pi = dev_prop.maxTexture3D[0];
        break;
    case mcDeviceAttributeMaxTexture3DHeight:
        *pi = dev_prop.maxTexture3D[1];
        break;
    case mcDeviceAttributeMaxTexture3DDepth:
        *pi = dev_prop.maxTexture3D[2];
        break;
    case mcDeviceAttributeHdpMemFlushCntl:
        *(unsigned int **)(pi) = dev_prop.hdpMemFlushCntl;
        break;
    case mcDeviceAttributeHdpRegFlushCntl:
        *(unsigned int **)(pi) = dev_prop.hdpRegFlushCntl;
        break;
    case mcDeviceAttributeMaxPitch:
        *pi = dev_prop.memPitch;
        break;
    case mcDeviceAttributeTextureAlignment:
        *pi = dev_prop.textureAlignment;
        break;
    case mcDeviceAttributeTexturePitchAlignment:
        *pi = dev_prop.texturePitchAlignment;
        break;
    case mcDeviceAttributeKernelExecTimeout:
        *pi = dev_prop.kernelExecTimeoutEnabled;
        break;
    case mcDeviceAttributeCanMapHostMemory:
        *pi = dev_prop.canMapHostMemory;
        break;
    case mcDeviceAttributeEccEnabled:
        *pi = dev_prop.ECCEnabled;
        break;
    case mcDeviceAttributeCooperativeMultiDeviceUnmatchedFunc:
        *pi = dev_prop.cooperativeMultiDeviceUnmatchedFunc;
        break;
    case mcDeviceAttributeCooperativeMultiDeviceUnmatchedGridDim:
        *pi = dev_prop.cooperativeMultiDeviceUnmatchedGridDim;
        break;
    case mcDeviceAttributeCooperativeMultiDeviceUnmatchedBlockDim:
        *pi = dev_prop.cooperativeMultiDeviceUnmatchedBlockDim;
        break;
    case mcDeviceAttributeCooperativeMultiDeviceUnmatchedSharedMem:
        *pi = dev_prop.cooperativeMultiDeviceUnmatchedSharedMem;
        break;
    case mcDeviceAttributeAsicRevision:
        *pi = dev_prop.asicRevision;
        break;
    case mcDeviceAttributeManagedMemory:
        *pi = dev_prop.managedMemory;
        break;
    case mcDeviceAttributeDirectManagedMemAccessFromHost:
        *pi = dev_prop.directManagedMemAccessFromHost;
        break;
    case mcDeviceAttributeConcurrentManagedAccess:
        *pi = dev_prop.concurrentManagedAccess;
        break;
    case mcDeviceAttributePageableMemoryAccess:
        *pi = dev_prop.pageableMemoryAccess;
        break;
    case mcDeviceAttributePageableMemoryAccessUsesHostPageTables:
        *pi = dev_prop.pageableMemoryAccessUsesHostPageTables;
        break;
    case mcDeviceAttributeCanUseStreamWaitValue:
        *pi = 1;
        break;
    case mcDeviceAttributeCanUseStreamMemOps:
        *pi = 1;
        break;
    case mcDeviceAttributeCanUseStreamWaitWaitValueNor:
        *pi = 1;
        break;
    case mcDeviceAttributeCanFlushRemoteWrites:
        *pi = 0;
        break;
    case mcDeviceAttributeMemoryPoolsSupported:
        *pi = 1;
        break;
    case mcDeviceAttributeUnifiedAddressing:
        *pi = dev_prop.unifiedAddressing;
        break;
    case mcDeviceAttributeMaxAccessPolicyWindowSize:
        *pi = dev_prop.accessPolicyMaxWindowSize;
        break;
    case mcDeviceAttributeMaxPersistingL2CacheSize:
        *pi = dev_prop.persistingL2CacheMaxSize;
        break;
    case mcDeviceAttributeGpuOverlap:
        *pi = dev_prop.deviceOverlap;
        break;
    case mcDeviceAttributeAsyncEngineCount:
        *pi = dev_prop.asyncEngineCount;
        break;
    case mcDeviceAttributeVirtualMemoryManagementSupported:
        *pi = 1;
        break;
    case mcDeviceAttributeHandleTypePosixFileDescriptorSupported:
        *pi = 1;
        break;
    case mcDeviceAttributeHandleTypeWin32HandleSupported:
        *pi = 0;
        break;
    case mcDeviceAttributeGenericCompressionSupported:
        *pi = 0;
        break;
    case mcDeviceAttributeTexture1DLinearWidth:
        *pi = dev_prop.maxTexture1DLinear;
        break;
    case mcDeviceAttributeTexture2DLinearWidth:
        *pi = dev_prop.maxTexture2DLinear[0];
        break;
    case mcDeviceAttributeTexture2DLinearHeight:
        *pi = dev_prop.maxTexture2DLinear[1];
        break;
    case mcDeviceAttributeTexture2DLinearPitch:
        *pi = dev_prop.maxTexture2DLinear[2];
        break;
    case mcDeviceAttributeHostNativeAtomicSupported:
        *pi = 1;
        break;
    case mcDeviceAttributeMaxTexture1DLayeredWidth:
        *pi = dev_prop.maxTexture1DLayered[0];
        break;
    case mcDeviceAttributeMaxTexture1DLayeredLayers:
        *pi = dev_prop.maxTexture1DLayered[1];
        break;
    case mcDeviceAttributeMaxTexture2DLayeredWidth:
        *pi = dev_prop.maxTexture2DLayered[0];
        break;
    case mcDeviceAttributeMaxTexture2DLayeredHeight:
        *pi = dev_prop.maxTexture2DLayered[1];
        break;
    case mcDeviceAttributeMaxTexture2DLayeredLayers:
        *pi = dev_prop.maxTexture2DLayered[2];
        break;
    case mcDeviceAttributeSurfaceAligement:
        *pi = dev_prop.surfaceAlignment;
        break;
    case mcDeviceAttributeComputePreemptionSupported:
        *pi = dev_prop.computePreemptionSupported;
        break;
    case mcDeviceAttributeCanUseHostPointerForRegisteredMem:
        *pi = 0;
        break;
    case mcDeviceAttributePciDomainId:
        *pi = dev_prop.pciDomainID;
        break;
    case mcDeviceAttributeTccDriver:
        *pi = dev_prop.tccDriver;
        break;
    case mcDevAttrMaxBlocksPerMultiprocessor:
        *pi = dev_prop.maxBlocksPerMultiProcessor;
        break;
    case mcDeviceAttributeMulticastSupported:
        /* currently multicast is not supported */
        *pi = 0;
        break;
    default:
        *pi = 0;
        break;
    }

    return MC_SUCCESS;
}

mcDrvError_t wcuDeviceGetUuid(mcDrvUuid_t *uuid, mcDrvDevice_t device)
{
    return mcErrorTomcDrvError(mcDeviceGetUuid(uuid, device));
}

mcDrvError_t wcuDeviceGetUuid_v2(mcDrvUuid_t *uuid, mcDrvDevice_t device)
{
    return mcErrorTomcDrvError(mcDeviceGetUuid(uuid, device));
}

mcDrvError_t wcuDeviceGetCount(int *count) { return mcErrorTomcDrvError(mcGetDeviceCount(count)); }

mcDrvError_t wcuDeviceGetByPCIBusId(mcDrvDevice_t *device, const char *pciBusId)
{
    return mcErrorTomcDrvError(mcDeviceGetByPCIBusId(device, pciBusId));
}

mcDrvError_t wcuDeviceGetExecAffinitySupport(int *pi, mcDrvexecAffinityType type, mcDrvDevice_t dev)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

mcDrvError_t wcuDeviceGetPCIBusId(char *pciBusId, int len, mcDrvDevice_t device)
{
    return mcErrorTomcDrvError(mcDeviceGetPCIBusId(pciBusId, len, device));
}

mcDrvError_t wcuDeviceGet(mcDrvDevice_t *device, int ordinal)
{
    return mcErrorTomcDrvError(mcDeviceGet(device, ordinal));
}

mcDrvError_t wcuDeviceGetName(char *name, int len, mcDrvDevice_t dev)
{
    return mcErrorTomcDrvError(mcDeviceGetName(name, len, dev));
}

mcDrvError_t wcuDeviceTotalMem(size_t *bytes, mcDrvDevice_t dev)
{
    return mcErrorTomcDrvError(mcDeviceTotalMem(bytes, dev));
}

mcDrvError_t wcuDeviceGetDefaultMemPool(mcDrvMemPool_t *poolOut, mcDrvDevice_t dev)
{
    return mcErrorTomcDrvError(mcDeviceGetDefaultMemPool(poolOut, dev));
}

mcDrvError_t wcuDeviceGetMemPool(mcDrvMemPool_t *poolOut, mcDrvDevice_t dev)
{
    return mcErrorTomcDrvError(mcDeviceGetMemPool(poolOut, dev));
}

mcDrvError_t wcuDeviceSetMemPool(mcDrvDevice_t dev, mcDrvMemPool_t poolOut)
{
    return mcErrorTomcDrvError(mcDeviceSetMemPool(dev, poolOut));
}

mcDrvError_t wcuDeviceGetLuid(char *luid, unsigned int *deviceNodeMask, mcDrvDevice_t dev)
{
    if ((luid == nullptr) || (deviceNodeMask == nullptr)) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }
    int count;
    cuDeviceGetCount(&count);
    if ((dev < 0) || (dev >= count)) {
        return mcErrorTomcDrvError(mcErrorInvalidDevice);
    }

    mcUuid_t uuid   = {0};
    auto err        = mcDeviceGetUuid(&uuid, dev);
    *deviceNodeMask = 1 << dev;
    if (err == mcSuccess) {
        memcpy(luid, uuid.bytes, sizeof(mcUuid_t));
    }
    return mcErrorTomcDrvError(err);
}

mcDrvError_t wcuDeviceGetP2PAttribute(int *value, mcDrvDeviceP2PAttribute attrib,
                                      mcDrvDevice_t srcDevice, mcDrvDevice_t dstDevice)
{
    return mcErrorTomcDrvError(
        mcDeviceGetP2PAttribute(value, static_cast<mcDeviceP2PAttr>(attrib), srcDevice, dstDevice));
}

mcDrvError_t wcuFlushGPUDirectRDMAWrites(mcDrvFlushGPUDirectRDMAWritesTarget target,
                                         mcDrvFlushGPUDirectRDMAWritesScope scope)
{
    return mcErrorTomcDrvError(
        mcDeviceFlushGPUDirectRDMAWrites(static_cast<mcFlushGPUDirectRDMAWritesTarget>(target),
                                         static_cast<mcFlushGPUDirectRDMAWritesScope>(scope)));
}

mcDrvError_t wcuDeviceGetNvSciSyncAttributes(void *mcSciSyncAttrList, mcDrvDevice_t dev, int flags)
{
    /* temp do not support this api, so just add wrapper here for complier*/
    return mcErrorTomcDrvError(mcSuccess);
}

mcDrvError_t wcuDeviceGetTexture1DLinearMaxWidth(size_t *maxWidthInElements, mcArray_Format format,
                                                 unsigned numChannels, mcDrvDevice_t dev)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

mcDrvError_t wcuDeviceComputeCapability(int *major, int *minor, mcDrvDevice_t dev)
{
    if (major == nullptr || minor == nullptr) {
        return MC_ERROR_INVALID_VALUE;
    }
    int count = 0;
    wcuDeviceGetCount(&count);
    if (dev < 0 || dev >= count) {
        return MC_ERROR_INVALID_DEVICE;
    }
    mcDeviceProp_t dev_prop = {};
    mcDeviceProp_t *prop    = &dev_prop;
    auto ret                = mcGetDeviceProperties(prop, dev);
    if (ret != mcSuccess) {
        return mcErrorTomcDrvError(ret);
    }

    *major = prop->major;
    *minor = prop->minor;
    if (__NV_ARCH_V100 == __nv_arch_type_internal__) {
        *major = 7;
        *minor = 0;
    } else if (__NV_ARCH_T4 == __nv_arch_type_internal__) {
        *major = 7;
        *minor = 5;
    } else if (__NV_ARCH_A100 == __nv_arch_type_internal__) {
        *major = 8;
        *minor = 0;
    }

    return mcErrorTomcDrvError(mcSuccess);
}
mcDrvError_t wcuDeviceGetProperties(mcDrvDevprop *prop, mcDrvDevice_t dev)
{
    /* TODO:wcuda_skipped - for deprecated */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

//---------------------------------------------------------------------------//
// Primary Context Managent
//---------------------------------------------------------------------------//
mcDrvError_t wcuDevicePrimaryCtxGetState(mcDrvDevice_t dev, unsigned int *flags, int *active)
{
    return mcErrorTomcDrvError(mcDevicePrimaryCtxGetState(dev, flags, active));
}

mcDrvError_t wcuDevicePrimaryCtxRelease(mcDrvDevice_t dev)
{
    return mcErrorTomcDrvError(mcDevicePrimaryCtxRelease(dev));
}

mcDrvError_t wcuDevicePrimaryCtxRetain(mcDrvContext_t *pctx, mcDrvDevice_t dev)
{
    return mcErrorTomcDrvError(mcDevicePrimaryCtxRetain(pctx, dev));
}

mcDrvError_t wcuDevicePrimaryCtxSetFlags(mcDrvDevice_t dev, unsigned int flags)
{
    return mcErrorTomcDrvError(mcDevicePrimaryCtxSetFlags(dev, flags));
}

mcDrvError_t wcuDevicePrimaryCtxReset(mcDrvDevice_t dev)
{
    return mcErrorTomcDrvError(mcDevicePrimaryCtxReset(dev));
}

//---------------------------------------------------------------------------//
// Context Managent
//---------------------------------------------------------------------------//

mcDrvError_t wcuCtxCreate(mcDrvContext_t *pctx, unsigned int flags, mcDrvDevice_t dev)
{
    auto ret = mcErrorTomcDrvError(mcCtxCreate(pctx, flags, dev));
    if (ret == MC_SUCCESS) {
        ACTIVE_CONTEXT();
    }

    return ret;
}

mcDrvError_t wcuCtxCreate_v3(mcDrvContext_t *pctx, mcDrvexecAffinityParam_t *paramsArray,
                             int numParams, unsigned int flags, mcDrvDevice_t dev)
{
    auto ret = mcErrorTomcDrvError(mcCtxCreate_v3(
        pctx, reinterpret_cast<mcExecAffinityParam *>(paramsArray), numParams, flags, dev));

    if (ret == MC_SUCCESS) {
        ACTIVE_CONTEXT();
    }

    return ret;
}

mcDrvError_t wcuCtxDestroy(mcDrvContext_t ctx) { return mcErrorTomcDrvError(mcCtxDestroy(ctx)); }

mcDrvError_t wcuCtxGetApiVersion(mcDrvContext_t ctx, unsigned int *version)
{
    return mcErrorTomcDrvError(mcCtxGetApiVersion(ctx, version));
}

mcDrvError_t wcuCtxGetCacheConfig(mcDrvfunc_cache_t *pconfig)
{
    return mcErrorTomcDrvError(mcCtxGetCacheConfig(reinterpret_cast<mcFuncCache_t *>(pconfig)));
}

mcDrvError_t wcuCtxGetCurrent(mcDrvContext_t *pctx)
{
    if (!g_hasContextBeenCreated) {
        *pctx = nullptr;
        return MC_SUCCESS;
    }
    return mcErrorTomcDrvError(mcCtxGetCurrent(pctx));
}

mcDrvError_t wcuCtxGetDevice(mcDrvDevice_t *device)
{
    return mcErrorTomcDrvError(mcCtxGetDevice(device));
}

mcDrvError_t wcuCtxGetExecAffinity(mcDrvexecAffinityParam_t *pExecAffinity,
                                   mcDrvexecAffinityType type)
{
    return mcErrorTomcDrvError(
        mcCtxGetExecAffinity(reinterpret_cast<mcExecAffinityParam_t *>(pExecAffinity),
                             static_cast<mcExecAffinityType>(type)));
}

mcDrvError_t wcuCtxGetFlags(unsigned int *flags)
{
    return mcErrorTomcDrvError(mcCtxGetFlags(flags));
}

mcDrvError_t wcuCtxGetLimit(size_t *pvalue, mcDrvlimit_t limit)
{

    return mcErrorTomcDrvError(mcDeviceGetLimit(pvalue, static_cast<mcLimit_t>(limit)));
}

mcDrvError_t wcuCtxGetSharedMemConfig(mcDrvsharedconfig_t *pConfig)
{
    return mcErrorTomcDrvError(
        mcCtxGetSharedMemConfig(reinterpret_cast<mcSharedMemConfig *>(pConfig)));
}

mcDrvError_t wcuCtxGetStreamPriorityRange(int *leastPriority, int *greatestPriority)
{
    return mcErrorTomcDrvError(mcCtxGetStreamPriorityRange(leastPriority, greatestPriority));
}

mcDrvError_t wcuCtxPopCurrent(mcDrvContext_t *pctx)
{
    return mcErrorTomcDrvError(mcCtxPopCurrent(pctx));
}

mcDrvError_t wcuCtxPushCurrent(mcDrvContext_t pctx)
{
    return mcErrorTomcDrvError(mcCtxPushCurrent(pctx));
}

mcDrvError_t wcuCtxResetPersistingL2Cache(void)
{
    return mcErrorTomcDrvError(mcCtxResetPersistingL2Cache());
}

mcDrvError_t wcuCtxSetCacheConfig(mcDrvfunc_cache_t config)
{
    return mcErrorTomcDrvError(mcCtxSetCacheConfig(static_cast<mcFuncCache_t>(config)));
}

mcDrvError_t wcuCtxSetCurrent(mcDrvContext_t ctx)
{
    return mcErrorTomcDrvError(mcCtxSetCurrent(ctx));
}

mcDrvError_t wcuCtxSetLimit(mcDrvlimit_t limit, size_t value)
{
    return mcErrorTomcDrvError(mcDeviceSetLimit(static_cast<mcLimit_t>(limit), value));
}

mcDrvError_t wcuCtxSetSharedMemConfig(mcDrvsharedconfig_t config)
{
    return mcErrorTomcDrvError(mcCtxSetSharedMemConfig(static_cast<mcSharedMemConfig>(config)));
}

mcDrvError_t wcuCtxSynchronize(void) { return mcErrorTomcDrvError(mcDeviceSynchronize()); }

mcDrvError_t wcuCtxAttach(mcDrvContext_t *pctx, unsigned int flags)
{
    /* TODO:wcuda_skipped - for deprecated */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuCtxDetach(mcDrvContext_t ctx)
{
    /* TODO:wcuda_skipped - for deprecated */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
//---------------------------------------------------------------------------//
// Module Managent
//---------------------------------------------------------------------------//
mcDrvError_t wcuModuleLoad(mcDrvModule_t *module, const char *fname)
{
    return mcErrorTomcDrvError(mcModuleLoad(module, fname));
}

mcDrvError_t wcuModuleLoadData(mcDrvModule_t *module, const void *image)
{
    return mcErrorTomcDrvError(mcModuleLoadData(module, image));
}
mcDrvError_t wcuModuleLoadDataEx(mcDrvModule_t *module, const void *image, unsigned int numOptions,
                                 mcDrvjit_option_t *options, void **optionValues)
{
    return mcErrorTomcDrvError(mcModuleLoadDataEx(
        module, image, numOptions, reinterpret_cast<mcJitOption *>(options), optionValues));
}
mcDrvError_t wcuModuleUnload(mcDrvModule_t hmod)
{
    return mcErrorTomcDrvError(mcModuleUnload(hmod));
}
mcDrvError_t wcuModuleGetFunction(mcDrvFunction_t *hfunc, mcDrvModule_t hmod, const char *name)
{
    return mcErrorTomcDrvError(mcModuleGetFunction(hfunc, hmod, name));
}

mcDrvError_t wcuLinkCreate(unsigned int numOptions, mcDrvjit_option_t *options, void **optionValues,
                           mcDrvlinkState_t *stateOut)
{
    return mcErrorTomcDrvError(
        mcLinkCreate(numOptions, reinterpret_cast<mcJitOption *>(options), optionValues, stateOut));
}

mcDrvError_t wcuLinkAddData(mcDrvlinkState_t state, mcDrvJitInputType_t type, void *data,
                            size_t size, const char *name, unsigned int numOptions,
                            mcDrvjit_option_t *options, void **optionValues)
{
    if ((type < MC_JIT_INPUT_BITCODE) || (type > MC_JIT_NUM_INPUT_TYPES)) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }
    return mcErrorTomcDrvError(
        mcLinkAddData(state, static_cast<mcJitInputType>(type), data, size, name, numOptions,
                      reinterpret_cast<mcJitOption *>(options), optionValues));
}

mcDrvError_t wcuLinkComplete(mcDrvlinkState_t state, void **binOut, size_t *sizeOut)
{
    return mcErrorTomcDrvError(mcLinkComplete(state, binOut, sizeOut));
}

mcDrvError_t wcuLinkAddFile(mcDrvlinkState_t state, mcDrvJitInputType_t type, const char *path,
                            unsigned int numOptions, mcDrvjit_option_t *options,
                            void **optionValues)
{
    if ((type < MC_JIT_INPUT_BITCODE) || (type > MC_JIT_NUM_INPUT_TYPES)) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }
    return mcErrorTomcDrvError(mcLinkAddFile(state, static_cast<mcJitInputType>(type), path,
                                             numOptions, reinterpret_cast<mcJitOption *>(options),
                                             optionValues));
}

mcDrvError_t wcuLinkDestroy(mcDrvlinkState_t state)
{
    return mcErrorTomcDrvError(mcLinkDestroy(state));
}

mcDrvError_t wcuModuleGetGlobal(mcDrvDeviceptr_t *dptr, size_t *bytes, mcDrvModule_t hmod,
                                const char *name)
{
    if (dptr == nullptr && bytes == nullptr) {
        return MC_ERROR_INVALID_VALUE;
    }

    if (hmod == nullptr) {
        return MC_ERROR_INVALID_HANDLE;
    }

    mcDrvError_t ret = MC_SUCCESS;

    if (dptr == nullptr && bytes != nullptr) {
        ret = mcErrorTomcDrvError(mcModuleGetGlobal(nullptr, bytes, hmod, name));
    } else {
        auto ptr = reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(*dptr));
        ret      = mcErrorTomcDrvError(mcModuleGetGlobal(&ptr, bytes, hmod, name));
        *dptr    = reinterpret_cast<uintptr_t>(ptr);
    }

    return ret;
}

mcDrvError_t wcuModuleGetSurfRef(mcDrvSurfref *pSurfRef, mcDrvModule_t hmod, const char *name)
{
    /* TODO:wcuda_skipped - for SurfRef */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

mcDrvError_t wcuModuleGetTexRef(mcDrvTexref *pTexRef, mcDrvModule_t hmod, const char *name)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

mcDrvError_t wcuModuleLoadFatBinary(mcDrvModule_t *module, const void *fatCubin)
{
    return mcErrorTomcDrvError(mcModuleLoadFatBinary(module, fatCubin));
}

//---------------------------------------------------------------------------//
// Memory Management
//---------------------------------------------------------------------------//
mcDrvError_t wcuArray3DCreate(MCarray *pHandle, const mcDrvArray3DDescriptor *pAllocateArray)
{
    if (pAllocateArray == nullptr) {
        return MC_ERROR_INVALID_VALUE;
    }

    mcArray **array = reinterpret_cast<mcArray **>(pHandle);
    mcChannelFormatDesc des =
        getChannelFormatDesc(pAllocateArray->NumChannels, pAllocateArray->Format);

    mcExtent extent;
    extent.width  = pAllocateArray->Width;
    extent.height = pAllocateArray->Height;
    extent.depth  = pAllocateArray->Depth;

    return mcErrorTomcDrvError(mcMalloc3DArray(array, &des, extent, pAllocateArray->Flags));
}

mcDrvError_t wcuArray3DGetDescriptor(mcDrvArray3DDescriptor *pArrayDescriptor, MCarray hArray)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

mcDrvError_t wcuArrayCreate(MCarray *pHandle, const mcDrvArrayDescriptor *pAllocateArray)
{
    if (pAllocateArray == nullptr) {
        return MC_ERROR_INVALID_VALUE;
    }

    mcArray **array = reinterpret_cast<mcArray **>(pHandle);
    mcChannelFormatDesc des =
        getChannelFormatDesc(pAllocateArray->NumChannels, pAllocateArray->Format);

    return mcErrorTomcDrvError(
        mcMallocArray(array, &des, pAllocateArray->Width, pAllocateArray->Height, mcArrayDefault));
}

mcDrvError_t wcuArrayDestroy(MCarray hArray)
{
    mcArray *array = reinterpret_cast<mcArray *>(hArray);
    return mcErrorTomcDrvError(mcFreeArray(array));
}

mcDrvError_t wcuArrayGetDescriptor(mcDrvArrayDescriptor *pArrayDescriptor, MCarray hArray)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuArrayGetMemoryRequirements(mcDrvArrayMemoryRequirements *memoryRequirements,
                                           MCarray array, mcDrvDevice_t device)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuArrayGetPlane(MCarray *pPlaneArray, MCarray hArray, unsigned int planeIdx)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuArrayGetSparseProperties(mcDrvArraySparseProperties *sparseProperties,
                                         MCarray array)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

mcDrvError_t wcuIpcCloseMemHandle(mcDrvDeviceptr_t dptr)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

mcDrvError_t wcuIpcGetMemHandle(mcDrvIpcMemHandle_t *pHandle, mcDrvDeviceptr_t dptr)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

mcDrvError_t wcuIpcOpenMemHandle(mcDrvDeviceptr_t *pdptr, mcDrvIpcMemHandle_t handle,
                                 unsigned int Flags)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

mcDrvError_t wcuMemAlloc(mcDrvDeviceptr_t *ptr, size_t sizeBytes)
{
    if (ptr == nullptr) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }
    auto temp_ptr = reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(*ptr));
    auto ret      = mcErrorTomcDrvError(mcMalloc(&temp_ptr, sizeBytes));
    *ptr          = reinterpret_cast<uintptr_t>(temp_ptr);
    return ret;
}

mcDrvError_t wcuMemAllocHost(void **pHost, size_t sizeBytes)
{
    return mcErrorTomcDrvError(mcMallocHost_v0(pHost, sizeBytes));
}

mcDrvError_t wcuMemAllocManaged(mcDrvDeviceptr_t *dptr, size_t sizeBytes, unsigned int flags)
{
    if (dptr == nullptr) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }
    auto temp_ptr = reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(*dptr));
    auto ret      = mcErrorTomcDrvError(mcMallocManaged(&temp_ptr, sizeBytes, flags));
    *dptr         = reinterpret_cast<uintptr_t>(temp_ptr);
    return ret;
}

mcDrvError_t wcuMemAllocPitch(mcDrvDeviceptr_t *dptr, size_t *pPitch, size_t widthInBytes,
                              size_t height, unsigned int elementSizeBytes)
{
    if (elementSizeBytes != 4 && elementSizeBytes != 8 && elementSizeBytes != 16) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }

    if (dptr == nullptr) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }
    auto temp_ptr = reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(*dptr));
    auto ret      = mcErrorTomcDrvError(mcMallocPitch(&temp_ptr, pPitch, widthInBytes, height));
    *dptr         = reinterpret_cast<uintptr_t>(temp_ptr);
    return ret;
}

mcDrvError_t wcuMemFree(mcDrvDeviceptr_t ptr)
{

    return mcErrorTomcDrvError(
        mcFree(reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(ptr))));
}

mcDrvError_t wcuMemFreeHost(void *ptr) { return mcErrorTomcDrvError(mcFreeHost(ptr)); }

mcDrvError_t wcuMemHostAlloc(void **pHost, size_t size, unsigned int flags)
{
    mcError_t status = mcSuccess;
    status           = mcMallocHost(pHost, size, flags);

    return mcErrorTomcDrvError(status);
}

mcDrvError_t wcuMemHostGetDevicePointer(mcDrvDeviceptr_t *pDevice, void *pHost, unsigned int flags)
{
    if (pDevice == nullptr) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }

    auto temp_ptr = reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(*pDevice));
    auto ret      = mcErrorTomcDrvError(mcHostGetDevicePointer(&temp_ptr, pHost, flags));
    *pDevice      = reinterpret_cast<uintptr_t>(temp_ptr);
    return ret;
}

mcDrvError_t wcuMemHostGetFlags(unsigned int *flagsPtr, void *hostPtr)
{
    return mcErrorTomcDrvError(mcHostGetFlags(flagsPtr, hostPtr));
}

mcDrvError_t wcuMemHostRegister(void *ptr, size_t size, unsigned int flags)
{
    return mcErrorTomcDrvError(mcHostRegister(ptr, size, flags));
}

mcDrvError_t wcuMemHostUnregister(void *ptr) { return mcErrorTomcDrvError(mcHostUnregister(ptr)); }

mcDrvError_t wcuMemcpy(mcDrvDeviceptr_t dst, mcDrvDeviceptr_t src, size_t sizeBytes)
{
    return mcErrorTomcDrvError(mcMemcpy(
        reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dst)),
        reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(src)), sizeBytes, mcMemcpyDefault));
}

bool validateMemoryType(mcMemoryType type)
{
    bool ret = false;
    switch (type) {
    case mcMemoryTypeHost:      // MC_MEMORYTYPE_HOST
    case mcMemoryTypeDevice:    // MC_MEMORYTYPE_DEVICE
    case mcMemoryTypeArray:     // MC_MEMORYTYPE_ARRAY
    case mcMemoryTypeUnified:   // MC_MEMORYTYPE_UNIFIED
    case mcMemoryTypeManaged:
        ret = true;
        break;
    default:
        ret = false;
        break;
    }
    return ret;
}

mcDrvError_t wcuMemcpy2D(const mcDrvMemcpy2D *pCopy)
{
    if (validateMemoryType(pCopy->srcMemoryType) == false ||
        validateMemoryType(pCopy->dstMemoryType) == false) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }

    mc_Memcpy2D copy{};
    copy.srcXInBytes   = pCopy->srcXInBytes;
    copy.srcY          = pCopy->srcY;
    copy.srcMemoryType = pCopy->srcMemoryType;
    copy.srcHost       = pCopy->srcHost;
    copy.srcDevice     = reinterpret_cast<void *>(static_cast<uintptr_t>(pCopy->srcDevice));
    copy.srcArray      = reinterpret_cast<mcArray_t>(pCopy->srcArray);
    copy.srcPitch      = pCopy->srcPitch;
    copy.dstXInBytes   = pCopy->dstXInBytes;
    copy.dstY          = pCopy->dstY;
    copy.dstMemoryType = pCopy->dstMemoryType;
    copy.dstHost       = pCopy->dstHost;
    copy.dstDevice     = reinterpret_cast<void *>(static_cast<uintptr_t>(pCopy->dstDevice));
    copy.dstArray      = reinterpret_cast<mcArray_t>(pCopy->dstArray);
    copy.dstPitch      = pCopy->dstPitch;
    copy.WidthInBytes  = pCopy->WidthInBytes;
    copy.Height        = pCopy->Height;

    return mcErrorTomcDrvError(mcMemcpyParam2D(&copy));
}

mcDrvError_t wcuMemcpy2DUnaligned(const mcDrvMemcpy2D *pCopy)
{
    mc_Memcpy2D copy{};

    if (validateMemoryType(pCopy->srcMemoryType) == false ||
        validateMemoryType(pCopy->dstMemoryType) == false) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }

    copy.srcXInBytes   = pCopy->srcXInBytes;
    copy.srcY          = pCopy->srcY;
    copy.srcMemoryType = pCopy->srcMemoryType;
    copy.srcHost       = pCopy->srcHost;
    copy.srcDevice     = reinterpret_cast<void *>(static_cast<uintptr_t>(pCopy->srcDevice));
    copy.srcArray      = reinterpret_cast<mcArray_t>(pCopy->srcArray);
    copy.srcPitch      = pCopy->srcPitch;
    copy.dstXInBytes   = pCopy->dstXInBytes;
    copy.dstY          = pCopy->dstY;
    copy.dstMemoryType = pCopy->dstMemoryType;
    copy.dstHost       = pCopy->dstHost;
    copy.dstDevice     = reinterpret_cast<void *>(static_cast<uintptr_t>(pCopy->dstDevice));
    copy.dstArray      = reinterpret_cast<mcArray_t>(pCopy->dstArray);
    copy.dstPitch      = pCopy->dstPitch;
    copy.WidthInBytes  = pCopy->WidthInBytes;
    copy.Height        = pCopy->Height;
    return mcErrorTomcDrvError(mcMemcpyParam2D(&copy));
}

mcDrvError_t wcuMemcpy2DAsync(const mcDrvMemcpy2D *pCopy, mcDrvStream_t hStream)
{
    mc_Memcpy2D param;

    if (validateMemoryType(pCopy->srcMemoryType) == false ||
        validateMemoryType(pCopy->dstMemoryType) == false) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }

    param.srcXInBytes   = pCopy->srcXInBytes;
    param.srcY          = pCopy->srcY;
    param.srcMemoryType = pCopy->srcMemoryType;
    param.srcHost       = pCopy->srcHost;
    param.srcDevice     = (mcDeviceptr_t)pCopy->srcDevice;
    param.srcArray      = (mcArray *)pCopy->srcArray;
    param.srcPitch      = pCopy->srcPitch;
    param.dstXInBytes   = pCopy->dstXInBytes;
    param.dstY          = pCopy->dstY;
    param.dstMemoryType = pCopy->dstMemoryType;
    param.dstHost       = pCopy->dstHost;
    param.dstDevice     = (mcDeviceptr_t)pCopy->dstDevice;
    param.dstArray      = (mcArray *)pCopy->dstArray;
    param.dstPitch      = pCopy->dstPitch;
    param.WidthInBytes  = pCopy->WidthInBytes;
    param.Height        = pCopy->Height;

    return mcErrorTomcDrvError(mcMemcpyParam2DAsync(&param, hStream));
}

static mc_Memcpy3D getMcMemcpy3D(const mcDrvMemcpy3D *pCopy)
{
    mc_Memcpy3D copy{};
    copy.srcXInBytes   = pCopy->srcXInBytes;
    copy.srcY          = pCopy->srcY;
    copy.srcZ          = pCopy->srcZ;
    copy.srcLOD        = pCopy->srcLOD;
    copy.srcMemoryType = pCopy->srcMemoryType;
    copy.srcHost       = pCopy->srcHost;
    copy.srcDevice     = reinterpret_cast<void *>(static_cast<uintptr_t>(pCopy->srcDevice));
    copy.srcArray      = reinterpret_cast<mcArray_t>(pCopy->srcArray);
    copy.srcPitch      = pCopy->srcPitch;
    copy.srcHeight     = pCopy->srcHeight;

    copy.dstXInBytes   = pCopy->dstXInBytes;
    copy.dstY          = pCopy->dstY;
    copy.dstZ          = pCopy->dstZ;
    copy.dstLOD        = pCopy->dstLOD;
    copy.dstMemoryType = pCopy->dstMemoryType;
    copy.dstHost       = pCopy->dstHost;
    copy.dstDevice     = reinterpret_cast<void *>(static_cast<uintptr_t>(pCopy->dstDevice));
    copy.dstArray      = reinterpret_cast<mcArray_t>(pCopy->dstArray);
    copy.dstPitch      = pCopy->dstPitch;
    copy.dstHeight     = pCopy->dstHeight;

    copy.WidthInBytes = pCopy->WidthInBytes;
    copy.Height       = pCopy->Height;
    copy.Depth        = pCopy->Depth;

    return copy;
}

mcDrvError_t wcuMemcpy3D(const mcDrvMemcpy3D *pCopy)
{

    if (validateMemoryType(pCopy->srcMemoryType) == false ||
        validateMemoryType(pCopy->dstMemoryType) == false) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }

    mc_Memcpy3D copy = getMcMemcpy3D(pCopy);

    return mcErrorTomcDrvError(mcMemcpyParam3D(&copy));
}

mcDrvError_t wcuMemcpy3DAsync(const mcDrvMemcpy3D *pCopy, mcDrvStream_t hStream)
{
    if (validateMemoryType(pCopy->srcMemoryType) == false ||
        validateMemoryType(pCopy->dstMemoryType) == false) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }
    mc_Memcpy3D copy = getMcMemcpy3D(pCopy);

    return mcErrorTomcDrvError(mcMemcpyParam3DAsync(&copy, hStream));
}

mcDrvError_t wcuMemcpy3DPeer(const mcDrvMemcpy3DPeer *pCopy)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuMemcpy3DPeerAsync(const mcDrvMemcpy3DPeer *pCopy, mcDrvStream_t hStream)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

mcDrvError_t wcuMemcpyAsync(mcDrvDeviceptr_t dst, mcDrvDeviceptr_t src, size_t byteCount,
                            mcDrvStream_t hStream)
{
    return mcErrorTomcDrvError(mcMemcpyAsync_v0(
        reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dst)),
        reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(src)), byteCount, hStream));
}

mcDrvError_t wcuMemGetInfo(size_t *free, size_t *total)
{
    return mcErrorTomcDrvError(mcMemGetInfo(free, total));
}

mcDrvError_t wcuMemGetAddressRange(mcDrvDeviceptr_t *pbase, size_t *psize, mcDrvDeviceptr_t dptr)
{
    if (!dptr) {
        return MC_ERROR_NOT_FOUND;
    }
    mcDeviceptr_t temp_ptr = nullptr;
    auto ret               = mcErrorTomcDrvError(mcMemGetAddressRange(
        &temp_ptr, psize, reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dptr))));
    if (pbase) {
        *pbase = reinterpret_cast<uintptr_t>(temp_ptr);
    }
    return ret;
}

mcDrvError_t wcuMemsetD16(mcDrvDeviceptr_t dstDevice, unsigned short us, size_t N)
{
    if (dstDevice & 0x1) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }
    return mcErrorTomcDrvError(
        mcMemsetD16(reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dstDevice)), us, N));
}

mcDrvError_t wcuMemsetD16Async(mcDrvDeviceptr_t dstDevice, unsigned short us, size_t N,
                               mcDrvStream_t hStream)
{
    if (dstDevice & 0x1) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }
    return mcErrorTomcDrvError(mcMemsetD16Async(
        reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dstDevice)), us, N, hStream));
}

mcDrvError_t wcuMemsetD32(mcDrvDeviceptr_t dstDevice, unsigned int ui, size_t N)
{
    if (dstDevice & 0x3) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }
    return mcErrorTomcDrvError(
        mcMemsetD32(reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dstDevice)), ui, N));
}

mcDrvError_t wcuMemsetD32Async(mcDrvDeviceptr_t dstDevice, unsigned int ui, size_t N,
                               mcDrvStream_t hStream)
{
    if (dstDevice & 0x3) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }
    return mcErrorTomcDrvError(mcMemsetD32Async(
        reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dstDevice)), ui, N, hStream));
}

mcDrvError_t wcuMemsetD8(mcDrvDeviceptr_t dstDevice, unsigned char uc, size_t N)
{
    return mcErrorTomcDrvError(
        mcMemsetD8(reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dstDevice)), uc, N));
}

mcDrvError_t wcuMemsetD8Async(mcDrvDeviceptr_t dstDevice, unsigned char uc, size_t N,
                              mcDrvStream_t hStream)
{
    return mcErrorTomcDrvError(mcMemsetD8Async(
        reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dstDevice)), uc, N, hStream));
}

mcDrvError_t wcuMemsetD2D8(mcDrvDeviceptr_t dstDevice, size_t dstPitch, unsigned char uc,
                           size_t Width, size_t Height)
{
    return mcErrorTomcDrvError(
        mcMemsetD2D8(reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dstDevice)), dstPitch,
                     uc, Width, Height));
}

mcDrvError_t wcuMemsetD2D8Async(mcDrvDeviceptr_t dstDevice, size_t dstPitch, unsigned char uc,
                                size_t Width, size_t Height, mcDrvStream_t hStream)
{
    return mcErrorTomcDrvError(
        mcMemsetD2D8Async(reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dstDevice)),
                          dstPitch, uc, Width, Height, hStream));
}

mcDrvError_t wcuMemsetD2D16(mcDrvDeviceptr_t dstDevice, size_t dstPitch, unsigned short us,
                            size_t Width, size_t Height)
{
    return mcErrorTomcDrvError(
        mcMemsetD2D16(reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dstDevice)), dstPitch,
                      us, Width, Height));
}

mcDrvError_t wcuMemsetD2D16Async(mcDrvDeviceptr_t dstDevice, size_t dstPitch, unsigned short us,
                                 size_t Width, size_t Height, mcDrvStream_t hStream)
{
    return mcErrorTomcDrvError(
        mcMemsetD2D16Async(reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dstDevice)),
                           dstPitch, us, Width, Height, hStream));
}

mcDrvError_t wcuMemsetD2D32(mcDrvDeviceptr_t dstDevice, size_t dstPitch, unsigned int ui,
                            size_t Width, size_t Height)
{
    return mcErrorTomcDrvError(
        mcMemsetD2D32(reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dstDevice)), dstPitch,
                      ui, Width, Height));
}

mcDrvError_t wcuMemsetD2D32Async(mcDrvDeviceptr_t dstDevice, size_t dstPitch, unsigned int ui,
                                 size_t Width, size_t Height, mcDrvStream_t hStream)
{
    return mcErrorTomcDrvError(
        mcMemsetD2D32Async(reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dstDevice)),
                           dstPitch, ui, Width, Height, hStream));
}

mcDrvError_t wcuMemcpyDtoA(MCarray dstArray, size_t dstOffset, mcDrvDeviceptr_t srcDevice,
                           size_t ByteCount)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuMemcpyAtoD(mcDrvDeviceptr_t dstDevice, MCarray srcArray, size_t srcOffset,
                           size_t ByteCount)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuMemcpyHtoA(MCarray dstArray, size_t dstOffset, const void *srcHost,
                           size_t ByteCount)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuMemcpyAtoH(void *dstHost, MCarray srcArray, size_t srcOffset, size_t ByteCount)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuMemcpyAtoA(MCarray dstArray, size_t dstOffset, MCarray srcArray, size_t srcOffset,
                           size_t ByteCount)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuMemcpyHtoAAsync(MCarray dstArray, size_t dstOffset, const void *srcHost,
                                size_t ByteCount, mcDrvStream_t hStream)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuMemcpyAtoHAsync(void *dstHost, MCarray srcArray, size_t srcOffset, size_t ByteCount,
                                mcDrvStream_t hStream)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

mcDrvError_t wcuMemcpyDtoD(mcDrvDeviceptr_t dstDevice, mcDrvDeviceptr_t srcDevice, size_t byteCount)
{
    return mcErrorTomcDrvError(mcMemcpyDtoD(
        reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dstDevice)),
        reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(srcDevice)), byteCount));
}

mcDrvError_t wcuMemcpyDtoDAsync(mcDrvDeviceptr_t dstDevice, mcDrvDeviceptr_t srcDevice,
                                size_t byteCount, mcDrvStream_t hStream)
{
    return mcErrorTomcDrvError(mcMemcpyDtoDAsync(
        reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dstDevice)),
        reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(srcDevice)), byteCount, hStream));
}

mcDrvError_t wcuMemcpyDtoH(void *dstHost, mcDrvDeviceptr_t srcDevice, size_t byteCount)
{
    return mcErrorTomcDrvError(mcMemcpyDtoH(
        dstHost, reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(srcDevice)), byteCount));
}

mcDrvError_t wcuMemcpyDtoHAsync(void *dstHost, mcDrvDeviceptr_t srcDevice, size_t byteCount,
                                mcDrvStream_t hStream)
{
    return mcErrorTomcDrvError(mcMemcpyDtoHAsync(
        dstHost, reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(srcDevice)), byteCount,
        hStream));
}

mcDrvError_t wcuMemcpyHtoD(mcDrvDeviceptr_t dstDevice, const void *srcHost, size_t byteCount)
{
    return mcErrorTomcDrvError(mcMemcpyHtoD(
        reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dstDevice)), srcHost, byteCount));
}

mcDrvError_t wcuMemcpyHtoDAsync(mcDrvDeviceptr_t dstDevice, const void *srcHost, size_t byteCount,
                                mcDrvStream_t hStream)
{
    return mcErrorTomcDrvError(
        mcMemcpyHtoDAsync(reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dstDevice)),
                          srcHost, byteCount, hStream));
}
mcDrvError_t wcuMemcpyPeer(mcDrvDeviceptr_t dstDevice, mcDrvContext_t dstContext,
                           mcDrvDeviceptr_t srcDevice, mcDrvContext_t srcContext, size_t byteCount)
{
    return mcErrorTomcDrvError(
        mcMemcpyPeer_v0(reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dstDevice)),
                        reinterpret_cast<mcCtx_t>(dstContext),
                        reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(srcDevice)),
                        reinterpret_cast<mcCtx_t>(dstContext), byteCount));
}

mcDrvError_t wcuMemcpyPeerAsync(mcDrvDeviceptr_t dstDevice, mcDrvContext_t dstContext,
                                mcDrvDeviceptr_t srcDevice, mcDrvContext_t srcContext,
                                size_t byteCount, mcDrvStream_t hStream)
{
    return mcErrorTomcDrvError(
        mcMemcpyPeerAsync_v0(reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dstDevice)),
                             reinterpret_cast<mcCtx_t>(dstContext),
                             reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(srcDevice)),
                             reinterpret_cast<mcCtx_t>(srcContext), byteCount, hStream));
}

mcDrvError_t wcuMipmappedArrayCreate(mcDrvMipmappedArray *pHandle,
                                     const mcDrvArray3DDescriptor *pMipmappedArrayDesc,
                                     unsigned int numMipmapLevels)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuMipmappedArrayDestroy(mcDrvMipmappedArray hMipmappedArray)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuMipmappedArrayGetLevel(MCarray *pLevelArray, mcDrvMipmappedArray hMipmappedArray,
                                       unsigned int level)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t
wcuMipmappedArrayGetMemoryRequirements(mcDrvArrayMemoryRequirements *memoryRequirements,
                                       mcDrvMipmappedArray mipmap, mcDrvDevice_t device)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuMipmappedArrayGetSparseProperties(mcDrvArraySparseProperties *sparseProperties,
                                                  mcDrvMipmappedArray mipmap)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

//---------------------------------------------------------------------------//
// Virtual Memory Management
//---------------------------------------------------------------------------//
mcDrvError_t wcuMemAddressFree(mcDrvDeviceptr_t ptr, size_t size)
{
    return mcErrorTomcDrvError(
        mcMemAddressFree(reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(ptr)), size));
}
mcDrvError_t wcuMemAddressReserve(mcDrvDeviceptr_t *ptr, size_t size, size_t alignment,
                                  mcDrvDeviceptr_t addr, unsigned long long flags)
{
    if (ptr == nullptr) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }
    auto temp_ptr = reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(*ptr));
    auto ret      = mcErrorTomcDrvError(
        mcMemAddressReserve(&temp_ptr, size, alignment,
                                 reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(addr)), flags));
    *ptr = reinterpret_cast<uintptr_t>(temp_ptr);
    return ret;
}
mcDrvError_t wcuMemMap(mcDrvDeviceptr_t ptr, size_t size, size_t offset,
                       mcDrvMemGenericAllocationHandle_t handle, unsigned long long flags)
{
    return mcErrorTomcDrvError(mcMemMap(
        reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(ptr)), size, offset, handle, flags));
}
mcDrvError_t wcuMemMapArrayAsync(mcDrvArrayMapInfo *mapInfoList, unsigned int count,
                                 mcDrvStream_t hStream)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuMemUnmap(mcDrvDeviceptr_t ptr, size_t size)
{
    return mcErrorTomcDrvError(
        mcMemUnmap(reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(ptr)), size));
}
mcDrvError_t wcuMemSetAccess(mcDrvDeviceptr_t ptr, size_t size, const mcDrvMemAccessDesc_t *desc,
                             size_t count)
{
    return mcErrorTomcDrvError(mcMemSetAccess(
        reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(ptr)), size, desc, count));
}
mcDrvError_t wcuMemGetAccess(unsigned long long *flags, const mcDrvMemLocation_t *location,
                             mcDrvDeviceptr_t ptr)
{
    return mcErrorTomcDrvError(mcMemGetAccess(
        flags, location, reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(ptr))));
}
mcDrvError_t wcuMemExportToShareableHandle(void *shareableHandle,
                                           mcDrvMemGenericAllocationHandle_t handle,
                                           mcDrvMemAllocationHandleType_t handleType,
                                           unsigned long long flags)
{
    return mcErrorTomcDrvError(
        mcMemExportToShareableHandle(shareableHandle, handle, handleType, flags));
}
mcDrvError_t wcuMemImportFromShareableHandle(mcDrvMemGenericAllocationHandle_t *handle,
                                             void *osHandle,
                                             mcDrvMemAllocationHandleType_t shHandleType)
{
    return mcErrorTomcDrvError(mcMemImportFromShareableHandle(handle, osHandle, shHandleType));
}
mcDrvError_t wcuMemGetAllocationGranularity(size_t *granularity,
                                            const mcDrvMemAllocationProp_t *prop,
                                            mcDrvMemAllocationGranularity_flags_t option)
{
    return mcErrorTomcDrvError(mcMemGetAllocationGranularity(granularity, prop, option));
}
mcDrvError_t wcuMemGetAllocationPropertiesFromHandle(mcDrvMemAllocationProp_t *prop,
                                                     mcDrvMemGenericAllocationHandle_t handle)
{
    return mcErrorTomcDrvError(mcMemGetAllocationPropertiesFromHandle(prop, handle));
}
mcDrvError_t wcuMemRetainAllocationHandle(mcDrvMemGenericAllocationHandle_t *handle, void *addr)
{
    return mcErrorTomcDrvError(mcMemRetainAllocationHandle(handle, addr));
}
mcDrvError_t wcuMemCreate(mcDrvMemGenericAllocationHandle_t *handle, size_t size,
                          const mcDrvMemAllocationProp_t *prop, unsigned long long flags)
{
    return mcErrorTomcDrvError(mcMemCreate(handle, size, prop, flags));
}

mcDrvError_t wcuMemRelease(mcDrvMemGenericAllocationHandle_t handle)
{
    return mcErrorTomcDrvError(mcMemRelease(handle));
}

//---------------------------------------------------------------------------//
// Multicast Object Management
//---------------------------------------------------------------------------//
mcDrvError_t wcuMulticastCreate(mcDrvMemGenericAllocationHandle_t *mcHandle,
                                const mcDrvMulticastObjectProp *prop)
{
    return mcErrorTomcDrvError(mcMulticastCreate(mcHandle, prop));
}
mcDrvError_t wcuMulticastAddDevice(mcDrvMemGenericAllocationHandle_t mcHandle, mcDrvDevice_t dev)
{
    return mcErrorTomcDrvError(mcMulticastAddDevice(mcHandle, dev));
}
mcDrvError_t wcuMulticastBindMem(mcDrvMemGenericAllocationHandle_t mcHandle, size_t mcOffset,
                                 mcDrvMemGenericAllocationHandle_t memHandle, size_t memOffset,
                                 size_t size, unsigned long long flags)
{
    return mcErrorTomcDrvError(
        mcMulticastBindMem(mcHandle, mcOffset, memHandle, memOffset, size, flags));
}
mcDrvError_t wcuMulticastBindAddr(mcDrvMemGenericAllocationHandle_t mcHandle, size_t mcOffset,
                                  mcDrvDeviceptr_t memptr, size_t size, unsigned long long flags)
{
    return mcErrorTomcDrvError(mcMulticastBindAddr(
        mcHandle, mcOffset, reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(memptr)), size,
        flags));
}
mcDrvError_t wcuMulticastUnbind(mcDrvMemGenericAllocationHandle_t mcHandle, mcDrvDevice_t dev,
                                size_t mcOffset, size_t size)
{
    return mcErrorTomcDrvError(mcMulticastUnbind(mcHandle, dev, mcOffset, size));
}
mcDrvError_t wcuMulticastGetGranularity(size_t *granularity, const mcDrvMulticastObjectProp *prop,
                                        mcDrvMulticastGranularity_flags option)
{
    return mcErrorTomcDrvError(mcMulticastGetGranularity(granularity, prop, option));
}

//---------------------------------------------------------------------------//
// Unified Addressing
//---------------------------------------------------------------------------//
static mcPointerAttributeType_t PointerAttributeTypeDrvToMc(mcDrvPointerAttributeType attr)
{
    switch (attr) {
    case MC_POINTER_ATTRIBUTE_MEMORY_TYPE:
        return mcPointerAttributeMemoryType;
    case MC_POINTER_ATTRIBUTE_DEVICE_POINTER:
        return mcPointerAttributeDevicePointer;
    case MC_POINTER_ATTRIBUTE_HOST_POINTER:
        return mcPointerAttributeHostPointer;
    case MC_POINTER_ATTRIBUTE_SYNC_MEMOPS:
        return mcPointerAttributeSyncMemops;
    case MC_POINTER_ATTRIBUTE_BUFFER_ID:
        return mcPointerAttributeBufferID;
    case MC_POINTER_ATTRIBUTE_IS_MANAGED:
        return mcPointerAttributeIsManaged;
    case MC_POINTER_ATTRIBUTE_RANGE_START_ADDR:
        return mcPointerAttributeRangeStartAddr;
    case MC_POINTER_ATTRIBUTE_RANGE_SIZE:
        return mcPointerAttributeRangeSize;
    case MC_POINTER_ATTRIBUTE_MAPPED:
        return mcPointerAttributeMapped;
    case MC_POINTER_ATTRIBUTE_DEVICE_ORDINAL:
        return mcPointerAttributeDevice;
    default:
        return mcPointerAttributeUnknow;
    }
}
static mcMemRangeAttribute_t MemRangeAttributeDrvToMc(mcDrvMemoryAttributeType_t attr)
{
    switch (attr) {
    case MC_MEM_RANGE_ATTRIBUTE_READ_MOSTLY:
        return mcMemRangeAttributeReadMostly;
    case MC_MEM_RANGE_ATTRIBUTE_PREFERRED_LOCATION:
        return mcMemRangeAttributePreferredLocation;
    case MC_MEM_RANGE_ATTRIBUTE_ACCESSED_BY:
        return mcMemRangeAttributeAccessedBy;
    case MC_MEM_RANGE_ATTRIBUTE_LAST_PREFETCH_LOCATION:
        return mcMemRangeAttributeLastPrefetchLocation;
    default:
        return mcMemRangeAttributeUnknow;
    }
}
static mcMemoryAdvise_t MemAdviseDrvToMc(mcDrvMemoryAdvise advise)
{
    switch (advise) {
    case MC_MEM_ADVISE_SET_READ_MOSTLY:
        return mcMemAdviseSetReadMostly;
    case MC_MEM_ADVISE_UNSET_READ_MOSTLY:
        return mcMemAdviseUnsetReadMostly;
    case MC_MEM_ADVISE_SET_PREFERRED_LOCATION:
        return mcMemAdviseSetPreferredLocation;
    case MC_MEM_ADVISE_UNSET_PREFERRED_LOCATION:
        return mcMemAdviseUnsetPreferredLocation;
    case MC_MEM_ADVISE_SET_ACCESSED_BY:
        return mcMemAdviseSetAccessedBy;
    case MC_MEM_ADVISE_UNSET_ACCESSED_BY:
        return mcMemAdviseUnsetAccessedBy;
    default:
        return mcMemAdviseUnknow;
    }
}
mcDrvError_t wcuMemAdvise(mcDrvDeviceptr_t devPtr, size_t count, mcDrvMemoryAdvise advice,
                          mcDrvDevice_t device)
{

    if (MemAdviseDrvToMc(advice) == mcMemAdviseUnknow) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }

    return mcErrorTomcDrvError(
        mcMemAdvise(reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(devPtr)), count,
                    MemAdviseDrvToMc(advice), device));
}

mcDrvError_t wcuPointerGetAttribute(void *data, mcDrvPointerAttributeType attribute,
                                    mcDrvDeviceptr_t ptr)
{
    if (PointerAttributeTypeDrvToMc(attribute) == mcPointerAttributeUnknow) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }
    mcError_t ret = mcPointerGetAttribute(data, PointerAttributeTypeDrvToMc(attribute),
                              reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(ptr)));
    if (attribute == MC_POINTER_ATTRIBUTE_MEMORY_TYPE)
    {
        if (*(mcMemoryType *)data == mcMemoryTypeUnified)
        {
            *(mcMemoryType *)data = mcMemoryTypeDevice;
        }
    }
    return mcErrorTomcDrvError(ret);
}

mcDrvError_t wcuPointerGetAttributes(unsigned int numAttributes,
                                     mcDrvPointerAttributeType *attributes, void **data,
                                     mcDrvDeviceptr_t ptr)
{
    if ((numAttributes == 0) || (attributes == nullptr) || (data == nullptr)) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }
    for (size_t i = 0; i < numAttributes; i++) {
        if (PointerAttributeTypeDrvToMc(attributes[i]) == mcPointerAttributeUnknow) {
            return mcErrorTomcDrvError(mcErrorInvalidValue);
        } else {
            mcPointerAttributeType_t attribute = PointerAttributeTypeDrvToMc(attributes[i]);
            if (mcPointerGetAttribute(
                    data[i], attribute,
                    reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(ptr))) != mcSuccess) {
                switch (attribute) {
                case mcPointerAttributeMemoryType:
                    *(mcMemoryType *)data[i] = mcMemoryTypeUnregistered;
                    break;
                case mcPointerAttributeDevice:
                    *(int *)data[i] = mcInvalidDeviceId;
                    break;
                case mcPointerAttributeDevicePointer:
                    *(char **)data[i] = nullptr;
                    break;
                case mcPointerAttributeHostPointer:
                    *(char **)data[i] = nullptr;
                    break;
                case mcPointerAttributeIsManaged:
                    *(bool *)data[i] = false;
                    break;
                case mcPointerAttributeMapped:
                    *(bool *)data[i] = false;
                    break;
                case mcPointerAttributeAllocationFlags:
                    *(unsigned int *)data[i] = 0;
                    break;
                case mcPointerAttributeRangeStartAddr:
                    break;
                case mcPointerAttributeRangeSize:
                    break;
                case mcPointerAttributeBufferID:
                    *(size_t *)data[i] = 0;
                    break;
                default:
                    return mcErrorTomcDrvError(mcErrorInvalidValue);
                    break;
                }
            }
            else
            {
                switch (attribute) {
                case mcPointerAttributeMemoryType:
                    if (*(mcMemoryType *)data[i] == mcMemoryTypeUnified)
                    {
                        // workaround to be compatible with cu driver
                        *(mcMemoryType *)data[i] = mcMemoryTypeDevice;
                    }
                    break;
                }
            }
        }
    }

    return mcErrorTomcDrvError(mcSuccess);
}
mcDrvError_t wcuMemPrefetchAsync(mcDrvDeviceptr_t devPtr, size_t count, mcDrvDevice_t dstDevice,
                                 mcDrvStream_t hStream)
{
    return mcErrorTomcDrvError(
        mcMemPrefetchAsync(reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(devPtr)), count,
                           dstDevice, hStream));
}

mcDrvError_t wcuMemRangeGetAttribute(void *data, size_t dataSize,
                                     mcDrvMemoryAttributeType_t attribute, mcDrvDeviceptr_t devPtr,
                                     size_t count)
{
    if (MemRangeAttributeDrvToMc(attribute) == mcMemRangeAttributeUnknow) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }

    return mcErrorTomcDrvError(mcMemRangeGetAttribute(
        data, dataSize, MemRangeAttributeDrvToMc(attribute),
        reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(devPtr)), count));
}

mcDrvError_t wcuMemRangeGetAttributes(void **data, size_t *dataSizes,
                                      mcDrvMemoryAttributeType_t *attributes, size_t numAttributes,
                                      mcDrvDeviceptr_t devPtr, size_t count)
{
    if ((numAttributes == 0) || (attributes == nullptr) || (dataSizes == nullptr)) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }
    mcMemRangeAttribute_t *attributes_t =
        (mcMemRangeAttribute_t *)malloc(numAttributes * sizeof(mcMemRangeAttribute_t));
    mcDrvError_t ret = MC_SUCCESS;

    for (int i = 0; i < numAttributes; i++) {
        *(attributes_t + i) = MemRangeAttributeDrvToMc(*(attributes + i));
        if ((*(attributes_t + i) == mcMemRangeAttributeUnknow) ||
            (*(dataSizes + i) < sizeof(unsigned int))) {
            ret = MC_ERROR_INVALID_VALUE;
            break;
        }
    }

    if (ret == MC_SUCCESS) {
        ret = mcErrorTomcDrvError(mcMemRangeGetAttributes(
            data, dataSizes, attributes_t, numAttributes,
            reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(devPtr)), count));
    }

    free(attributes_t);
    return ret;
}

mcDrvError_t wcuPointerSetAttribute(const void *value, mcDrvPointerAttributeType attribute,
                                    mcDrvDeviceptr_t ptr)
{
    if (PointerAttributeTypeDrvToMc(attribute) == mcPointerAttributeUnknow) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }
    return mcErrorTomcDrvError(
        mcPointerSetAttribute(const_cast<void *>(value), PointerAttributeTypeDrvToMc(attribute),
                              reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(ptr))));
}
//---------------------------------------------------------------------------//
// Stream Management
//---------------------------------------------------------------------------//
mcDrvError_t wcuStreamBeginCapture(mcDrvStream_t hStream, mcStreamCaptureMode mode)
{
    return mcErrorTomcDrvError(mcStreamBeginCapture(hStream, mode));
}
mcDrvError_t wcuStreamCreate(mcDrvStream_t *phStream, unsigned int Flags)
{
    return mcErrorTomcDrvError(mcStreamCreateWithFlags(phStream, Flags));
}

mcDrvError_t wcuStreamCreateWithPriority(mcDrvStream_t *phStream, unsigned int flags, int priority)
{
    return mcErrorTomcDrvError(mcStreamCreateWithPriority(phStream, flags, priority));
}

mcDrvError_t wcuStreamDestroy(mcDrvStream_t hStream)
{
    return mcErrorTomcDrvError(mcStreamDestroy(hStream));
}

mcDrvError_t wcuStreamEndCapture(mcDrvStream_t hStream, mcDrvGraph *phGraph)
{
    return mcErrorTomcDrvError(mcStreamEndCapture(hStream, phGraph));
}
mcDrvError_t wcuStreamGetCaptureInfo(mcDrvStream_t hStream,
                                     mcStreamCaptureStatus *captureStatus_out, mcuint64_t *id_out)
{
    return mcErrorTomcDrvError(mcStreamGetCaptureInfo(
        hStream, captureStatus_out, reinterpret_cast<unsigned long long *>(id_out)));
}
mcDrvError_t wcuStreamGetCaptureInfo_v2(mcDrvStream_t hStream,
                                        mcStreamCaptureStatus *captureStatus_out,
                                        mcuint64_t *id_out, mcDrvGraph *graph_out,
                                        const mcDrvGraphNode **dependencies_out,
                                        size_t *numDependencies_out)
{
    return mcErrorTomcDrvError(mcStreamGetCaptureInfo(
        hStream, captureStatus_out, reinterpret_cast<unsigned long long *>(id_out), graph_out,
        dependencies_out, numDependencies_out));
}
mcDrvError_t wcuStreamGetFlags(mcDrvStream_t hStream, unsigned int *flags)
{
    return mcErrorTomcDrvError(mcStreamGetFlags(hStream, flags));
}

mcDrvError_t wcuStreamGetPriority(mcDrvStream_t hStream, int *priority)
{
    return mcErrorTomcDrvError(mcStreamGetPriority(hStream, priority));
}

mcDrvError_t wcuStreamIsCapturing(mcDrvStream_t hStream, mcStreamCaptureStatus *captureStatus)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuStreamQuery(mcDrvStream_t hStream)
{
    return mcErrorTomcDrvError(mcStreamQuery(hStream));
}

mcDrvError_t wcuStreamSynchronize(mcDrvStream_t hStream)
{
    return mcErrorTomcDrvError(mcStreamSynchronize(hStream));
}

mcDrvError_t wcuStreamWaitEvent(mcDrvStream_t hStream, mcDrvEvent_t hEvent, unsigned int Flags)
{
    return mcErrorTomcDrvError(mcStreamWaitEvent(hStream, hEvent, Flags));
}

mcDrvError_t wcuStreamAddCallback(mcDrvStream_t hStream, mcDrvStreamCallback_t callback,
                                  void *userData, unsigned int flags)
{
    return mcErrorTomcDrvError(mcStreamAddCallback(
        hStream, reinterpret_cast<mcStreamCallback_t>(callback), userData, flags));
}

mcDrvError_t wcuStreamAttachMemAsync(mcDrvStream_t hStream, mcDrvDeviceptr_t dptr, size_t length,
                                     unsigned int flags)
{
    return mcErrorTomcDrvError(mcStreamAttachMemAsync(
        hStream, reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dptr)), length, flags));
}
mcDrvError_t wcuStreamCopyAttributes(mcDrvStream_t dst, mcDrvStream_t src)
{
    return mcErrorTomcDrvError(mcStreamCopyAttributes(dst, src));
}

mcDrvError_t wcuStreamSetAttribute(mcDrvStream_t hStream, mcDrvStreamAttrID attr,
                                   const mcDrvStreamAttrValue *value)
{
    return mcErrorTomcDrvError(mcStreamSetAttribute(hStream, attr, value));
}

mcDrvError_t wcuStreamGetAttribute(mcDrvStream_t hStream, mcDrvStreamAttrID attr,
                                   mcDrvStreamAttrValue *value_out)
{

    return mcErrorTomcDrvError(mcStreamGetAttribute(hStream, attr, value_out));
}

mcDrvError_t wcuStreamGetCtx(mcDrvStream_t hStream, mcDrvContext_t *pctx)
{
    return mcErrorTomcDrvError(mcStreamGetCtx(hStream, pctx));
}

mcDrvError_t wcuStreamUpdateCaptureDependencies(mcDrvStream_t hStream, mcDrvGraphNode *dependencies,
                                                size_t numDependencies, unsigned int flags)
{
    return mcErrorTomcDrvError(
        mcStreamUpdateCaptureDependencies(hStream, dependencies, numDependencies, flags));
}

mcDrvError_t wcuThreadExchangeStreamCaptureMode(mcStreamCaptureMode *mode)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

//---------------------------------------------------------------------------//
// Event Management
//---------------------------------------------------------------------------//
mcDrvError_t wcuIpcGetEventHandle(mcDrvIpcEventHandle_t *pHandle, mcDrvEvent_t event)
{
    return mcErrorTomcDrvError(mcIpcGetEventHandle(pHandle, event));
}

mcDrvError_t wcuIpcOpenEventHandle(mcDrvEvent_t *phEvent, mcDrvIpcEventHandle_t handle)
{
    return mcErrorTomcDrvError(mcIpcOpenEventHandle(phEvent, handle));
}

mcDrvError_t wcuEventCreate(mcDrvEvent_t *event, unsigned int flags)
{
    return mcErrorTomcDrvError(mcEventCreate(event, flags));
}

mcDrvError_t wcuEventDestroy(mcDrvEvent_t event)
{
    return mcErrorTomcDrvError(mcEventDestroy(event));
}

mcDrvError_t wcuEventElapsedTime(float *ms, mcDrvEvent_t start, mcDrvEvent_t end)
{
    if (ms == nullptr) {
        return mcErrorTomcDrvError(mcErrorInvalidResourceHandle);
    }
    return mcErrorTomcDrvError(mcEventElapsedTime(ms, start, end));
}

mcDrvError_t wcuEventQuery(mcDrvEvent_t event) { return mcErrorTomcDrvError(mcEventQuery(event)); }

mcDrvError_t wcuEventRecord(mcDrvEvent_t event, mcDrvStream_t stream)
{
    return mcErrorTomcDrvError(mcEventRecord(event, stream));
}

mcDrvError_t wcuEventRecordWithFlags(mcDrvEvent_t hEvent, mcDrvStream_t hStream, unsigned int flags)
{

    return mcErrorTomcDrvError(mcEventRecordWithFlags(hEvent, hStream, flags));
}

mcDrvError_t wcuEventSynchronize(mcDrvEvent_t event)
{
    return mcErrorTomcDrvError(mcEventSynchronize(event));
}

//---------------------------------------------------------------------------//
// External Resource Interoperability
//---------------------------------------------------------------------------//
mcDrvError_t wcuDestroyExternalMemory(mcDrvExternalMemory extMem)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

mcDrvError_t wcuDestroyExternalSemaphore(mcDrvExternalSemaphore extSem)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

mcDrvError_t wcuExternalMemoryGetMappedBuffer(mcDrvDeviceptr_t *devPtr, mcDrvExternalMemory extMem,
                                              const mcDrvExternalMemoryBufferDesc *bufferDesc)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

mcDrvError_t
wcuExternalMemoryGetMappedMipmappedArray(mcDrvMipmappedArray *mipmap, mcDrvExternalMemory extMem,
                                         const mcDrvExternalMemoryMipmappedArrayDesc *mipmapDesc)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

mcDrvError_t wcuImportExternalMemory(mcDrvExternalMemory *extMem_out,
                                     const mcDrvExternalMemoryHandleDesc *memHandleDesc)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

mcDrvError_t wcuImportExternalSemaphore(mcDrvExternalSemaphore *extSem_out,
                                        const mcDrvExternalSemaphorHandleDesc *semHandleDesc)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

mcDrvError_t wcuSignalExternalSemaphoresAsync(const mcDrvExternalSemaphore *extSemArray,
                                              const mcDrvExternalSemaphoreSignalParams *paramsArray,
                                              unsigned int numExtSems, mcDrvStream_t stream)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

mcDrvError_t wcuWaitExternalSemaphoresAsync(const mcDrvExternalSemaphore *extSemArray,
                                            const mcDrvExternalSemaphoreWaitParams *paramsArray,
                                            unsigned int numExtSems, mcDrvStream_t stream)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

//---------------------------------------------------------------------------//
// Execution Control
//---------------------------------------------------------------------------//
mcDrvError_t wcuFuncGetAttribute(int *value, mcDrvFunction_attribute attrib, mcDrvFunction_t hfunc)
{

    return mcErrorTomcDrvError(mcFuncGetAttribute(value, attrib, hfunc));
}

mcDrvError_t wcuLaunchKernel(mcDrvFunction_t f, unsigned int gridDimX, unsigned int gridDimY,
                             unsigned int gridDimZ, unsigned int blockDimX, unsigned int blockDimY,
                             unsigned int blockDimZ, unsigned int sharedMemBytes,
                             mcDrvStream_t stream, void **kernelParams, void **extra)
{
    return mcErrorTomcDrvError(mcModuleLaunchKernel(f, gridDimX, gridDimY, gridDimZ, blockDimX,
                                                    blockDimY, blockDimZ, sharedMemBytes, stream,
                                                    kernelParams, extra));
}

mcDrvError_t wcuFuncGetModule(mcDrvModule_t *hmod, mcDrvFunction_t hfunc)
{
    return mcErrorTomcDrvError(mcFuncGetModule(hmod, hfunc));
}

mcDrvError_t wcuFuncSetAttribute(mcDrvFunction_t hfunc, mcDrvFunction_attribute attrib, int value)
{
    if (hfunc == nullptr) {
        return mcErrorTomcDrvError(mcErrorInvalidDeviceFunction);
    }

    if (attrib != MC_FUNC_ATTRIBUTE_MAX_DYNAMIC_SHARED_SIZE_BYTES &&
        attrib != MC_FUNC_ATTRIBUTE_PREFERRED_SHARED_MEMORY_CARVEOUT) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }

    return mcErrorTomcDrvError(mcSuccess);
}

mcDrvError_t wcuFuncSetCacheConfig(mcDrvFunction_t hfunc, mcDrvfunc_cache_t config)
{
    if (hfunc == nullptr) {
        return mcErrorTomcDrvError(mcErrorInvalidDeviceFunction);
    }

    if (config != MC_FUNC_CACHE_PREFER_NONE && config != MC_FUNC_CACHE_PREFER_SHARED &&
        config != MC_FUNC_CACHE_PREFER_L1 && config != MC_FUNC_CACHE_PREFER_EQUAL) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }

    return mcErrorTomcDrvError(mcSuccess);
}

mcDrvError_t wcuFuncSetSharedMemConfig(mcDrvFunction_t hfunc, mcDrvsharedconfig_t config)
{
    if (hfunc == nullptr) {
        return mcErrorTomcDrvError(mcErrorInvalidDeviceFunction);
    }

    if (config != MC_SHARED_MEM_CONFIG_FOUR_BYTE_BANK_SIZE &&
        config != MC_SHARED_MEM_CONFIG_EIGHT_BYTE_BANK_SIZE &&
        config != MC_SHARED_MEM_CONFIG_DEFAULT_BANK_SIZE) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }

    return mcErrorTomcDrvError(mcSuccess);
}

mcDrvError_t wcuLaunchCooperativeKernel(mcDrvFunction_t f, unsigned int gridDimX,
                                        unsigned int gridDimY, unsigned int gridDimZ,
                                        unsigned int blockDimX, unsigned int blockDimY,
                                        unsigned int blockDimZ, unsigned int sharedMemBytes,
                                        mcDrvStream_t stream, void **kernelParams)
{
    return mcErrorTomcDrvError(mcLaunchCooperativeKernel(f, dim3(gridDimX, gridDimY, gridDimZ),
                                                         dim3(blockDimX, blockDimY, blockDimZ),
                                                         kernelParams, sharedMemBytes, stream));
}

mcDrvError_t wcuLaunchHostFunc(mcDrvStream_t hStream, mcHostFn_t fn, void *userData)
{

    return mcErrorTomcDrvError(mcLaunchHostFunc(hStream, fn, userData));
}

mcDrvError_t wcuLaunchCooperativeKernelMultiDevice(mcDrvLaunchParams *launchParamsList,
                                                   unsigned int numDevices, unsigned int flags)
{
    /* TODO:wcuda_skipped - for deprecated in CUDA 11.3 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

/* deprecated */
mcDrvError_t wcuFuncSetBlockShape(mcDrvFunction_t hfunc, int x, int y, int z)
{
    /* TODO:wcuda_skipped - for deprecated */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuFuncSetSharedSize(mcDrvFunction_t hfunc, unsigned int bytes)
{
    /* TODO:wcuda_skipped - for deprecated */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuLaunch(mcDrvFunction_t f)
{
    /* TODO:wcuda_skipped - for deprecated */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuLaunchGrid(mcDrvFunction_t f, int grid_width, int grid_height)
{
    /* TODO:wcuda_skipped - for deprecated */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuLaunchGridAsync(mcDrvFunction_t f, int grid_width, int grid_height,
                                mcDrvStream_t hStream)
{
    /* TODO:wcuda_skipped - for deprecated */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuParamSetf(mcDrvFunction_t hfunc, int offset, float value)
{
    /* TODO:wcuda_skipped - for deprecated */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuParamSeti(mcDrvFunction_t hfunc, int offset, unsigned int value)
{
    /* TODO:wcuda_skipped - for deprecated */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuParamSetSize(mcDrvFunction_t hfunc, unsigned int numbytes)
{
    /* TODO:wcuda_skipped - for deprecated */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuParamSetTexRef(mcDrvFunction_t hfunc, int texunit, mcDrvTexref hTexRef)
{
    /* TODO:wcuda_skipped - for deprecated */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuParamSetv(mcDrvFunction_t hfunc, int offset, void *ptr, unsigned int numbytes)
{
    /* TODO:wcuda_skipped - for deprecated */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

//---------------------------------------------------------------------------//
// Occupancy
//---------------------------------------------------------------------------//

//---------------------------------------------------------------------------//
// Peer Device Memory Access
//---------------------------------------------------------------------------//
mcDrvError_t wcuDeviceCanAccessPeer(int *canAccessPeer, mcDrvDevice_t dev, mcDrvDevice_t peerDev)
{

    return mcErrorTomcDrvError(mcDeviceCanAccessPeer(canAccessPeer, dev, peerDev));
}

mcDrvError_t wcuCtxEnablePeerAccess(mcDrvContext_t peerContext, unsigned int Flags)
{

    return mcErrorTomcDrvError(mcCtxEnablePeerAccess(peerContext, Flags));
}

mcDrvError_t wcuCtxDisablePeerAccess(mcDrvContext_t peerContext)
{
    return mcErrorTomcDrvError(mcCtxDisablePeerAccess(peerContext));
}

//---------------------------------------------------------------------------//
//  Driver Entry Point Access
//---------------------------------------------------------------------------//
extern std::map<std::string, std::map<unsigned int, void *>> cuApiWrapperMap;
mcDrvError_t wcuGetProcAddress(const char *symbol, void **pfn, int mcVersion, uint64_t flags)
{
    return mcErrorTomcDrvError(mcGetProcAddress_v0(cuApiWrapperMap, symbol, pfn, mcVersion, flags));
}

mcDrvError_t wcuGetExportTable(const void **ppExportTable, const mcDrvUuid_t *pExportTableId)
{
    /* TODO:wcuda-bwang1 */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

//---------------------------------------------------------------------------//
// Profiler Control
//---------------------------------------------------------------------------//
mcDrvError_t wcuProfilerInitialize(const char *configFile, const char *outputFile,
                                   mcOutputMode_t outputMode)
{
    return mcErrorTomcDrvError(mcProfilerInitialize(configFile, outputFile, outputMode));
}

mcDrvError_t wcuProfilerStart(void) { return mcErrorTomcDrvError(mcProfilerStart()); }
mcDrvError_t wcuProfilerStop(void) { return mcErrorTomcDrvError(mcProfilerStop()); }

//---------------------------------------------------------------------------//
// Stream Ordered Memory Allocator
//---------------------------------------------------------------------------//
mcDrvError_t wcuMemAllocAsync(mcDrvDeviceptr_t *dptr, size_t bytesize, mcDrvStream_t hStream)
{
    mcDrvError_t ret = mcErrorTomcDrvError(mcErrorInvalidValue);
    if (dptr != nullptr) {
        auto temp_ptr = reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(*dptr));
        ret           = mcErrorTomcDrvError(mcMemAllocAsync(&temp_ptr, bytesize, hStream));
        *dptr         = reinterpret_cast<uintptr_t>(temp_ptr);
    }
    return ret;
}

mcDrvError_t wcuMemAllocFromPoolAsync(mcDrvDeviceptr_t *dptr, size_t bytesize, mcDrvMemPool_t pool,
                                      mcDrvStream_t hStream)
{
    mcDrvError_t ret = mcErrorTomcDrvError(mcErrorInvalidValue);
    if (dptr != nullptr) {
        auto temp_ptr = reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(*dptr));
        ret   = mcErrorTomcDrvError(mcMemAllocFromPoolAsync(&temp_ptr, bytesize, pool, hStream));
        *dptr = reinterpret_cast<uintptr_t>(temp_ptr);
    }
    return ret;
}

mcDrvError_t wcuMemFreeAsync(mcDrvDeviceptr_t dptr, mcDrvStream_t hStream)
{

    return mcErrorTomcDrvError(
        mcFreeAsync(reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(dptr)), hStream));
}

mcDrvError_t wcuMemPoolCreate(mcDrvMemPool_t *pool, const mcDrvMemPoolProps_t *poolProps)
{
    return mcErrorTomcDrvError(mcMemPoolCreate(pool, poolProps));
}

mcDrvError_t wcuMemPoolDestroy(mcDrvMemPool_t pool)
{
    return mcErrorTomcDrvError(mcMemPoolDestroy(pool));
}

mcDrvError_t wcuMemPoolExportPointer(mcDrvMemPoolPtrExportData_t *shareData_out,
                                     mcDrvDeviceptr_t ptr)
{

    return mcErrorTomcDrvError(mcMemPoolExportPointer(
        shareData_out, reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(ptr))));
}

mcDrvError_t wcuMemPoolExportToShareableHandle(void *handle_out, mcDrvMemPool_t pool,
                                               mcDrvMemAllocationHandleType_t handleType,
                                               unsigned long long flags)
{
    return mcErrorTomcDrvError(
        mcMemPoolExportToShareableHandle(handle_out, pool, handleType, (unsigned int)flags));
}

mcDrvError_t wcuMemPoolImportFromShareableHandle(mcDrvMemPool_t *pool_out, void *handle,
                                                 mcDrvMemAllocationHandleType_t handleType,
                                                 unsigned long long flags)
{
    return mcErrorTomcDrvError(
        mcMemPoolImportFromShareableHandle(pool_out, handle, handleType, (unsigned int)flags));
}

mcDrvError_t wcuMemPoolImportPointer(mcDrvDeviceptr_t *ptr_out, mcDrvMemPool_t pool,
                                     mcDrvMemPoolPtrExportData_t *shareData)
{

    if (ptr_out == nullptr) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }
    auto temp_ptr = reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(*ptr_out));
    auto ret      = mcErrorTomcDrvError(mcMemPoolImportPointer(&temp_ptr, pool, shareData));
    *ptr_out      = reinterpret_cast<mcDrvDeviceptr_t>(temp_ptr);
    return ret;
}

mcDrvError_t wcuMemPoolGetAccess(mcDrvMemAccess_flags_t *flags, mcDrvMemPool_t memPool,
                                 mcDrvMemLocation_t *location)
{
    return mcErrorTomcDrvError(mcMemPoolGetAccess(flags, memPool, location));
}
mcDrvError_t wcuMemPoolGetAttribute(mcDrvMemPool_t pool, mcDrvMemPoolAttr_t attr, void *value)
{
    return mcErrorTomcDrvError(
        mcMemPoolGetAttribute(pool, static_cast<mcMemPoolAttr>(attr), value));
}
mcDrvError_t wcuMemPoolSetAccess(mcDrvMemPool_t pool, const mcDrvMemAccessDesc_t *map, size_t count)
{

    if (map == nullptr) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }
    return mcErrorTomcDrvError(mcMemPoolSetAccess(pool, map, count));
}
mcDrvError_t wcuMemPoolSetAttribute(mcDrvMemPool_t pool, mcDrvMemPoolAttr_t attr, void *value)
{

    return mcErrorTomcDrvError(
        mcMemPoolSetAttribute(pool, static_cast<mcMemPoolAttr>(attr), value));
}
mcDrvError_t wcuMemPoolTrimTo(mcDrvMemPool_t pool, size_t minBytesToKeep)
{
    return mcErrorTomcDrvError(mcMemPoolTrimTo(pool, minBytesToKeep));
}

//---------------------------------------------------------------------------//
// Stream Memory Opertions
//---------------------------------------------------------------------------//
mcDrvError_t wcuStreamBatchMemOp(mcDrvStream_t stream, unsigned int count,
                                 mcDrvStreamBatchMemOpParams *paramArray, unsigned int flags)
{
    return mcErrorTomcDrvError(mcStreamBatchMemOp(stream, count, paramArray, flags));
}
mcDrvError_t wcuStreamWaitValue32(mcDrvStream_t stream, mcDrvDeviceptr_t addr, uint32_t value,
                                  unsigned int flags)
{

    return mcErrorTomcDrvError(mcStreamWaitValue32(
        stream, reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(addr)), value, flags));
}
mcDrvError_t wcuStreamWaitValue64(mcDrvStream_t stream, mcDrvDeviceptr_t addr, uint64_t value,
                                  unsigned int flags)
{

    return mcErrorTomcDrvError(mcStreamWaitValue64(
        stream, reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(addr)), value, flags));
}
mcDrvError_t wcuStreamWriteValue32(mcDrvStream_t stream, mcDrvDeviceptr_t addr, uint32_t value,
                                   unsigned int flags)
{

    return mcErrorTomcDrvError(mcStreamWriteValue32(
        stream, reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(addr)), value, flags));
}
mcDrvError_t wcuStreamWriteValue64(mcDrvStream_t stream, mcDrvDeviceptr_t addr, uint64_t value,
                                   unsigned int flags)
{

    return mcErrorTomcDrvError(mcStreamWriteValue64(
        stream, reinterpret_cast<mcDeviceptr_t>(static_cast<uintptr_t>(addr)), value, flags));
}

//---------------------------------------------------------------------------//
// Occupancy Function Driver Wrappers
//---------------------------------------------------------------------------//

mcDrvError_t wcuOccupancyAvailableDynamicSMemPerBlock(size_t *dynamicSmemSize, mcDrvFunction_t func,
                                                      int numBlocks, int blockSize)
{
    return mcErrorTomcDrvError(
        mcOccupancyAvailableDynamicSMemPerBlock_v0(dynamicSmemSize, func, numBlocks, blockSize));
}

mcDrvError_t wcuOccupancyMaxActiveBlocksPerMultiprocessor(int *numBlocks, mcDrvFunction_t func,
                                                          int blockSize, size_t dynamicSMemSize)
{
    return mcErrorTomcDrvError(mcOccupancyMaxActiveBlocksPerMultiprocessor_v0(
        numBlocks, func, blockSize, dynamicSMemSize));
}

mcDrvError_t wcuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags(
    int *numBlocks, mcDrvFunction_t func, int blockSize, size_t dynamicSMemSize, unsigned int flags)
{
    return mcErrorTomcDrvError(mcOccupancyMaxActiveBlocksPerMultiprocessorWithFlags_v0(
        numBlocks, func, blockSize, dynamicSMemSize, flags));
}

mcDrvError_t wcuOccupancyMaxPotentialBlockSize(int *minGridSize, int *blockSize,
                                               mcDrvFunction_t func,
                                               mcOccupancyB2DSize blockSizeToDynamicSMemSize,
                                               size_t dynamicSMemSize, int blockSizeLimit)
{
    return mcErrorTomcDrvError(mcOccupancyMaxPotentialBlockSize_v0(
        minGridSize, blockSize, func, blockSizeToDynamicSMemSize, dynamicSMemSize, blockSizeLimit));
}

mcDrvError_t
wcuOccupancyMaxPotentialBlockSizeWithFlags(int *minGridSize, int *blockSize, mcDrvFunction_t func,
                                           mcOccupancyB2DSize blockSizeToDynamicSMemSize,
                                           size_t dynamicSMemSize, int blockSizeLimit,
                                           unsigned int flags)
{
    return mcErrorTomcDrvError(mcOccupancyMaxPotentialBlockSizeWithFlags_v0(
        minGridSize, blockSize, func, blockSizeToDynamicSMemSize, dynamicSMemSize, blockSizeLimit,
        flags));
}

//---------------------------------------------------------------------------//
// graph
//---------------------------------------------------------------------------//
mcDrvError_t wcuDeviceGetGraphMemAttribute(mcDrvDevice_t device, mcDrvGraphMem_attribute attr,
                                           void *value)
{
    mcGraphMemAttributeType mcAttr;
    switch (attr) {
    case MC_GRAPH_MEM_ATTR_USED_MEM_CURRENT:
        mcAttr = mcGraphMemAttrUsedMemCurrent;
        break;
    case MC_GRAPH_MEM_ATTR_USED_MEM_HIGH:
        mcAttr = mcGraphMemAttrUsedMemHigh;
        break;
    case MC_GRAPH_MEM_ATTR_RESERVED_MEM_CURRENT:
        mcAttr = mcGraphMemAttrReservedMemCurrent;
        break;
    case MC_GRAPH_MEM_ATTR_RESERVED_MEM_HIGH:
        mcAttr = mcGraphMemAttrReservedMemHigh;
        break;
    default:
        break;
    }
    return mcErrorTomcDrvError(mcDeviceGetGraphMemAttribute(device, mcAttr, value));
}

mcDrvError_t wcuDeviceGraphMemTrim(mcDrvDevice_t device)
{
    return mcErrorTomcDrvError(mcDeviceGraphMemTrim(device));
}

mcDrvError_t wcuDeviceSetGraphMemAttribute(mcDrvDevice_t device, mcDrvGraphMem_attribute attr,
                                           void *value)
{
    mcGraphMemAttributeType mcAttr;
    switch (attr) {
    case MC_GRAPH_MEM_ATTR_USED_MEM_CURRENT:
        mcAttr = mcGraphMemAttrUsedMemCurrent;
        break;
    case MC_GRAPH_MEM_ATTR_USED_MEM_HIGH:
        mcAttr = mcGraphMemAttrUsedMemHigh;
        break;
    case MC_GRAPH_MEM_ATTR_RESERVED_MEM_CURRENT:
        mcAttr = mcGraphMemAttrReservedMemCurrent;
        break;
    case MC_GRAPH_MEM_ATTR_RESERVED_MEM_HIGH:
        mcAttr = mcGraphMemAttrReservedMemHigh;
        break;
    default:
        break;
    }
    return mcErrorTomcDrvError(mcDeviceSetGraphMemAttribute(device, mcAttr, value));
}

mcDrvError_t wcuGraphAddChildGraphNode(mcDrvGraphNode *phGraphNode, mcDrvGraph hGraph,
                                       const mcDrvGraphNode *dependencies, size_t numDependencies,
                                       mcDrvGraph childGraph)
{
    return mcErrorTomcDrvError(
        mcGraphAddChildGraphNode(phGraphNode, hGraph, dependencies, numDependencies, childGraph));
}

mcDrvError_t wcuGraphAddDependencies(mcDrvGraph hGraph, const mcDrvGraphNode *from,
                                     const mcDrvGraphNode *to, size_t numDependencies)
{

    return mcErrorTomcDrvError(mcGraphAddDependencies(hGraph, from, to, numDependencies));
}

mcDrvError_t wcuGraphAddEmptyNode(mcDrvGraphNode *phGraphNode, mcDrvGraph hGraph,
                                  const mcDrvGraphNode *dependencies, size_t numDependencies)
{
    return mcErrorTomcDrvError(
        mcGraphAddEmptyNode(phGraphNode, hGraph, dependencies, numDependencies));
}

mcDrvError_t wcuGraphAddEventRecordNode(mcDrvGraphNode *phGraphNode, mcDrvGraph hGraph,
                                        const mcDrvGraphNode *dependencies, size_t numDependencies,
                                        mcDrvEvent_t event)
{
    return mcErrorTomcDrvError(
        mcGraphAddEventRecordNode(phGraphNode, hGraph, dependencies, numDependencies, event));
}

mcDrvError_t wcuGraphAddEventWaitNode(mcDrvGraphNode *phGraphNode, mcDrvGraph hGraph,
                                      const mcDrvGraphNode *dependencies, size_t numDependencies,
                                      mcDrvEvent_t event)
{
    return mcErrorTomcDrvError(
        mcGraphAddEventWaitNode(phGraphNode, hGraph, dependencies, numDependencies, event));
}

mcDrvError_t wcuGraphAddExternalSemaphoresSignalNode(mcDrvGraphNode *phGraphNode, mcDrvGraph hGraph,
                                                     const mcDrvGraphNode *dependencies,
                                                     size_t numDependencies,
                                                     const mcDrvExtSemSignalNodeParams *nodeParams)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuGraphAddExternalSemaphoresWaitNode(mcDrvGraphNode *phGraphNode, mcDrvGraph hGraph,
                                                   const mcDrvGraphNode *dependencies,
                                                   size_t numDependencies,
                                                   const mcDrvExtSemWaitNodeParams *nodeParams)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuGraphAddHostNode(mcDrvGraphNode *phGraphNode, mcDrvGraph hGraph,
                                 const mcDrvGraphNode *dependencies, size_t numDependencies,
                                 const mcDrvHostNodeParams *nodeParams)
{
    return mcErrorTomcDrvError(
        mcGraphAddHostNode(phGraphNode, hGraph, dependencies, numDependencies,
                           reinterpret_cast<const mcHostNodeParams *>(nodeParams)));
}

mcDrvError_t wcuGraphAddKernelNode(mcDrvGraphNode *phGraphNode, mcDrvGraph hGraph,
                                   const mcDrvGraphNode *dependencies, size_t numDependencies,
                                   const mcDrvKernelNodeParams *nodeParams)
{
    mcKernelNodeParams params;
    params.func     = nodeParams->func;
    params.gridDim  = dim3(nodeParams->gridDimX, nodeParams->gridDimY, nodeParams->gridDimZ);
    params.blockDim = dim3(nodeParams->blockDimX, nodeParams->blockDimY, nodeParams->blockDimZ);
    params.sharedMemBytes = nodeParams->sharedMemBytes;
    params.kernelParams   = nodeParams->kernelParams;
    params.extra          = nodeParams->extra;

    return mcErrorTomcDrvError(
        mcGraphAddKernelNode(phGraphNode, hGraph, dependencies, numDependencies, &params));
}

mcDrvError_t wcuGraphAddMemAllocNode(mcDrvGraphNode *phGraphNode, mcDrvGraph hGraph,
                                     const mcDrvGraphNode *dependencies, size_t numDependencies,
                                     mcDrvMemAllocNodeParams *nodeParams)
{
    mcMemAllocNodeParams params;
    params.poolProps       = nodeParams->poolProps;
    params.accessDescs     = nodeParams->accessDescs;
    params.accessDescCount = nodeParams->accessDescCount;
    params.bytesize        = nodeParams->bytesize;

    mcError_t err =
        mcGraphAddMemAllocNode(phGraphNode, hGraph, dependencies, numDependencies, &params);
    nodeParams->dptr = reinterpret_cast<mcDrvDeviceptr_t>(params.dptr);
    return mcErrorTomcDrvError(err);
}

mcDrvError_t wcuGraphAddMemFreeNode(mcDrvGraphNode *phGraphNode, mcDrvGraph hGraph,
                                    const mcDrvGraphNode *dependencies, size_t numDependencies,
                                    mcDrvDeviceptr_t dptr)
{
    return mcErrorTomcDrvError(mcGraphAddMemFreeNode(
        phGraphNode, hGraph, dependencies, numDependencies, reinterpret_cast<void *>(dptr)));
}

mcMemcpy3DParms getMemcpy3DParms(const mcDrvMemcpy3D *copyParams)
{
    mcMemcpy3DParms params;
    memset(&params, 0, sizeof(mcMemcpy3Dparms));

    bool isSrcHost = false, isDstHost = false;
    if (copyParams->dstMemoryType == mcMemoryTypeArray) {
        params.dstArray = reinterpret_cast<mcArray_t>(copyParams->dstArray);
    } else if (copyParams->dstMemoryType == mcMemoryTypeHost) {
        params.dstPtr = {const_cast<void *>(copyParams->dstHost), copyParams->dstPitch,
                         copyParams->dstPitch, copyParams->dstHeight};
        isDstHost     = true;
    } else {
        params.dstPtr = {reinterpret_cast<void *>(copyParams->dstDevice), copyParams->dstPitch,
                         copyParams->dstPitch, copyParams->dstHeight};
    }

    if (copyParams->srcMemoryType == mcMemoryTypeArray) {
        params.srcArray = reinterpret_cast<mcArray_t>(copyParams->dstArray);
    } else if (copyParams->srcMemoryType == mcMemoryTypeHost) {
        params.srcPtr = {const_cast<void *>(copyParams->srcHost), copyParams->srcPitch,
                         copyParams->srcPitch, copyParams->srcHeight};
        isSrcHost     = true;
    } else {
        params.srcPtr = {reinterpret_cast<void *>(copyParams->srcDevice), copyParams->srcPitch,
                         copyParams->srcPitch, copyParams->srcHeight};
    }

    params.srcPos.x = copyParams->srcXInBytes;
    params.srcPos.y = copyParams->srcY;
    params.srcPos.z = copyParams->srcZ;

    params.extent.width  = copyParams->WidthInBytes;
    params.extent.height = copyParams->Height;
    params.extent.depth  = copyParams->Depth;

    if (isSrcHost && isDstHost) {
        params.kind = mcMemcpyHostToHost;
    } else if (isSrcHost && !isDstHost) {
        params.kind = mcMemcpyHostToDevice;
    } else if (!isSrcHost && isDstHost) {
        params.kind = mcMemcpyDeviceToHost;
    } else {
        params.kind = mcMemcpyDeviceToDevice;
    }

    return params;
}

mcDrvError_t wcuGraphAddMemcpyNode(mcDrvGraphNode *phGraphNode, mcDrvGraph hGraph,
                                   const mcDrvGraphNode *dependencies, size_t numDependencies,
                                   const mcDrvMemcpy3D *copyParams, mcDrvContext_t ctx)
{
    if (validateMemoryType(copyParams->srcMemoryType) == false ||
        validateMemoryType(copyParams->dstMemoryType) == false) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }

    const mcMemcpy3DParms params = getMemcpy3DParms(copyParams);

    return mcErrorTomcDrvError(
        mcGraphAddMemcpyNode(phGraphNode, hGraph, dependencies, numDependencies, &params));
}

mcDrvError_t wcuGraphAddMemsetNode(mcDrvGraphNode *phGraphNode, mcDrvGraph hGraph,
                                   const mcDrvGraphNode *dependencies, size_t numDependencies,
                                   const mcDrvMemsetNodeParams *memsetParams, mcDrvContext_t ctx)
{
    mcMemsetParams params;
    params.dst         = reinterpret_cast<void *>(memsetParams->dst);
    params.value       = memsetParams->value;
    params.elementSize = memsetParams->elementSize;
    params.pitch       = memsetParams->pitch;
    params.width       = memsetParams->width;
    params.height      = memsetParams->height;

    return mcErrorTomcDrvError(
        mcGraphAddMemsetNode(phGraphNode, hGraph, dependencies, numDependencies, &params));
}

mcDrvError_t wcuGraphChildGraphNodeGetGraph(mcDrvGraphNode hNode, mcDrvGraph *phGraph)
{

    return mcErrorTomcDrvError(mcGraphChildGraphNodeGetGraph(hNode, phGraph));
}

mcDrvError_t wcuGraphClone(mcDrvGraph *phGraphClone, mcDrvGraph originalGraph)
{
    return mcErrorTomcDrvError(mcGraphClone(phGraphClone, originalGraph));
}

mcDrvError_t wcuGraphCreate(mcDrvGraph *phGraph, unsigned int flags)
{
    return mcErrorTomcDrvError(mcGraphCreate(phGraph, flags));
}

mcDrvError_t wcuGraphDebugDotPrint(mcDrvGraph hGraph, const char *path, unsigned int flags)
{

    return mcErrorTomcDrvError(mcGraphDebugDotPrint(hGraph, path, flags));
}

mcDrvError_t wcuGraphDestroy(mcDrvGraph hGraph)
{
    return mcErrorTomcDrvError(mcGraphDestroy(hGraph));
}

mcDrvError_t wcuGraphDestroyNode(mcDrvGraphNode hNode)
{
    return mcErrorTomcDrvError(mcGraphDestroyNode(hNode));
}

mcDrvError_t wcuGraphEventRecordNodeGetEvent(mcDrvGraphNode hNode, mcDrvEvent_t *event_out)
{

    return mcErrorTomcDrvError(mcGraphEventRecordNodeGetEvent(hNode, event_out));
}

mcDrvError_t wcuGraphEventRecordNodeSetEvent(mcDrvGraphNode hNode, mcDrvEvent_t event)
{

    return mcErrorTomcDrvError(mcGraphEventRecordNodeSetEvent(hNode, event));
}

mcDrvError_t wcuGraphEventWaitNodeGetEvent(mcDrvGraphNode hNode, mcDrvEvent_t *event_out)
{

    return mcErrorTomcDrvError(mcGraphEventWaitNodeGetEvent(hNode, event_out));
}

mcDrvError_t wcuGraphEventWaitNodeSetEvent(mcDrvGraphNode hNode, mcDrvEvent_t event)
{

    return mcErrorTomcDrvError(mcGraphEventWaitNodeSetEvent(hNode, event));
}

mcDrvError_t wcuGraphExecChildGraphNodeSetParams(mcDrvGraphExec hGraphExec, mcDrvGraphNode hNode,
                                                 mcDrvGraph childGraph)
{
    return mcErrorTomcDrvError(mcGraphExecChildGraphNodeSetParams(hGraphExec, hNode, childGraph));
}

mcDrvError_t wcuGraphExecDestroy(mcDrvGraphExec hGraphExec)
{
    return mcErrorTomcDrvError(mcGraphExecDestroy(hGraphExec));
}

mcDrvError_t wcuGraphExecEventRecordNodeSetEvent(mcDrvGraphExec hGraphExec, mcDrvGraphNode hNode,
                                                 mcDrvEvent_t event)
{
    return mcErrorTomcDrvError(mcGraphExecEventRecordNodeSetEvent(hGraphExec, hNode, event));
}

mcDrvError_t wcuGraphExecEventWaitNodeSetEvent(mcDrvGraphExec hGraphExec, mcDrvGraphNode hNode,
                                               mcDrvEvent_t event)
{
    return mcErrorTomcDrvError(mcGraphExecEventWaitNodeSetEvent(hGraphExec, hNode, event));
}

mcDrvError_t
wcuGraphExecExternalSemaphoresSignalNodeSetParams(mcDrvGraphExec hGraphExec, mcDrvGraphNode hNode,
                                                  const mcDrvExtSemSignalNodeParams *nodeParams)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t
wcuGraphExecExternalSemaphoresWaitNodeSetParams(mcDrvGraphExec hGraphExec, mcDrvGraphNode hNode,
                                                const mcDrvExtSemWaitNodeParams *nodeParams)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuGraphExecHostNodeSetParams(mcDrvGraphExec hGraphExec, mcDrvGraphNode hNode,
                                           const mcDrvHostNodeParams *nodeParams)
{

    return mcErrorTomcDrvError(mcGraphExecHostNodeSetParams(
        hGraphExec, hNode, reinterpret_cast<const mcHostNodeParams *>(nodeParams)));
}

mcDrvError_t wcuGraphExecKernelNodeSetParams(mcDrvGraphExec hGraphExec, mcDrvGraphNode hNode,
                                             const mcDrvKernelNodeParams *nodeParams)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuGraphExecMemcpyNodeSetParams(mcDrvGraphExec hGraphExec, mcDrvGraphNode hNode,
                                             const mcDrvMemcpy3D *copyParams, mcDrvContext_t ctx)
{
    if (validateMemoryType(copyParams->srcMemoryType) == false ||
        validateMemoryType(copyParams->dstMemoryType) == false) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }

    mcMemcpy3DParms params = getMemcpy3DParms(copyParams);
    return mcErrorTomcDrvError(mcGraphExecMemcpyNodeSetParams(hGraphExec, hNode, &params));
}

mcDrvError_t wcuGraphExecMemsetNodeSetParams(mcDrvGraphExec hGraphExec, mcDrvGraphNode hNode,
                                             const mcDrvMemsetNodeParams *memsetParams,
                                             mcDrvContext_t ctx)
{
    mcMemsetParams params;
    params.dst         = reinterpret_cast<void *>(memsetParams->dst);
    params.value       = memsetParams->value;
    params.elementSize = memsetParams->elementSize;
    params.pitch       = memsetParams->pitch;
    params.width       = memsetParams->width;
    params.height      = memsetParams->height;
    return mcErrorTomcDrvError(mcGraphExecMemsetNodeSetParams(hGraphExec, hNode, &params));
}

mcDrvError_t wcuGraphExecUpdate(mcDrvGraphExec hGraphExec, mcDrvGraph hGraph,
                                mcDrvGraphNode *hErrorNode_out,
                                mcGraphExecUpdateResult *updateResult_out)
{
    return mcErrorTomcDrvError(
        mcGraphExecUpdate(hGraphExec, hGraph, hErrorNode_out, updateResult_out));
}

mcDrvError_t wcuGraphExternalSemaphoresSignalNodeGetParams(mcDrvGraphNode hNode,
                                                           mcDrvExtSemSignalNodeParams *params_out)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t
wcuGraphExternalSemaphoresSignalNodeSetParams(mcDrvGraphNode hNode,
                                              const mcDrvExtSemSignalNodeParams *nodeParams)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuGraphExternalSemaphoresWaitNodeGetParams(mcDrvGraphNode hNode,
                                                         mcDrvExtSemWaitNodeParams *params_out)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t
wcuGraphExternalSemaphoresWaitNodeSetParams(mcDrvGraphNode hNode,
                                            const mcDrvExtSemWaitNodeParams *nodeParams)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuGraphGetEdges(mcDrvGraph hGraph, mcDrvGraphNode *from, mcDrvGraphNode *to,
                              size_t *numEdges)
{

    return mcErrorTomcDrvError(mcGraphGetEdges(hGraph, from, to, numEdges));
}

mcDrvError_t wcuGraphGetNodes(mcDrvGraph hGraph, mcDrvGraphNode *nodes, size_t *numNodes)
{

    return mcErrorTomcDrvError(mcGraphGetNodes(hGraph, nodes, numNodes));
}

mcDrvError_t wcuGraphGetRootNodes(mcDrvGraph hGraph, mcDrvGraphNode *rootNodes,
                                  size_t *numRootNodes)
{

    return mcErrorTomcDrvError(mcGraphGetRootNodes(hGraph, rootNodes, numRootNodes));
}

mcDrvError_t wcuGraphHostNodeGetParams(mcDrvGraphNode hNode, mcDrvHostNodeParams *nodeParams)
{

    return mcErrorTomcDrvError(
        mcGraphHostNodeGetParams(hNode, reinterpret_cast<mcHostNodeParams *>(nodeParams)));
}

mcDrvError_t wcuGraphHostNodeSetParams(mcDrvGraphNode hNode, const mcDrvHostNodeParams *nodeParams)
{

    return mcErrorTomcDrvError(
        mcGraphHostNodeSetParams(hNode, reinterpret_cast<const mcHostNodeParams *>(nodeParams)));
}

mcDrvError_t wcuGraphInstantiate(mcDrvGraphExec *phGraphExec, mcDrvGraph hGraph,
                                 mcDrvGraphNode *phErrorNode, char *logBuffer, size_t bufferSize)
{
    return mcErrorTomcDrvError(
        mcGraphInstantiate(phGraphExec, hGraph, phErrorNode, logBuffer, bufferSize));
}

mcDrvError_t wcuGraphInstantiateWithFlags(mcDrvGraphExec *phGraphExec, mcDrvGraph hGraph,
                                          unsigned long long flags)
{

    return mcErrorTomcDrvError(mcGraphInstantiateWithFlags(phGraphExec, hGraph, flags));
}

mcDrvError_t wcuGraphInstantiateWithParams(mcDrvGraphExec *phGraphExec, mcDrvGraph hGraph,
                                           mcDrvGraphInstantiateParams *instantiateParams)
{

    if (instantiateParams == nullptr) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }
    mcGraphInstantiateParams params{0};
    params.errNode_out  = instantiateParams->hErrNode_out;
    params.flags        = instantiateParams->flags;
    params.result_out   = instantiateParams->result_out;
    params.uploadStream = instantiateParams->hUploadStream;
    mcDrvError_t ret =
        mcErrorTomcDrvError(mcGraphInstantiateWithParams(phGraphExec, hGraph, &params));
    instantiateParams->hErrNode_out = params.errNode_out;
    instantiateParams->result_out   = params.result_out;
    return ret;
}

mcDrvError_t wcuGraphExecGetFlags(mcDrvGraphExec hGraphExec, mcuint64_t *flags)
{

    return mcErrorTomcDrvError(
        mcGraphExecGetFlags(hGraphExec, reinterpret_cast<unsigned long long *>(flags)));
}

mcDrvError_t wcuGraphKernelNodeCopyAttributes(mcDrvGraphNode dst, mcDrvGraphNode src)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuGraphKernelNodeGetAttribute(mcDrvGraphNode hNode, mcDrvkernelNodeAttrID attr,
                                            mcDrvKernelNodeAttrValue *value_out)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuGraphKernelNodeGetParams(mcDrvGraphNode hNode, mcDrvKernelNodeParams *nodeParams)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuGraphKernelNodeSetAttribute(mcDrvGraphNode hNode, mcDrvkernelNodeAttrID attr,
                                            const mcDrvKernelNodeAttrValue *value)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuGraphKernelNodeSetParams(mcDrvGraphNode hNode,
                                         const mcDrvKernelNodeParams *nodeParams)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuGraphLaunch(mcDrvGraphExec hGraphExec, mcDrvStream_t hStream)
{
    return mcErrorTomcDrvError(mcGraphLaunch(hGraphExec, hStream));
}

mcDrvError_t wcuGraphMemAllocNodeGetParams(mcDrvGraphNode hNode,
                                           mcDrvMemAllocNodeParams *params_out)
{
    mcMemAllocNodeParams params;
    mcError_t err = mcGraphMemAllocNodeGetParams(hNode, &params);
    if (err == mcSuccess) {
        params_out->poolProps       = params.poolProps;
        params_out->dptr            = reinterpret_cast<unsigned long long>(params.dptr);
        params_out->bytesize        = params.bytesize;
        params_out->accessDescs     = params.accessDescs;
        params_out->accessDescCount = params.accessDescCount;
    }
    return mcErrorTomcDrvError(err);
}

mcDrvError_t wcuGraphMemFreeNodeGetParams(mcDrvGraphNode hNode, mcDrvDeviceptr_t *dptr_out)
{
    return mcErrorTomcDrvError(
        mcGraphMemFreeNodeGetParams(hNode, reinterpret_cast<void *>(dptr_out)));
}

mcDrvError_t wcuGraphMemcpyNodeGetParams(mcDrvGraphNode hNode, mcDrvMemcpy3D *nodeParams)
{
    mcMemcpy3DParms params;
    memset(&params, 0, sizeof(mcMemcpy3Dparms));

    mcError_t err = mcGraphMemcpyNodeGetParams(hNode, &params);
    if (err == mcSuccess) {
        MACA_MEMCPY3D tmpParams   = getMACAMemcpy3DDesc(params);
        nodeParams->Depth         = tmpParams.Depth;
        nodeParams->Height        = tmpParams.Height;
        nodeParams->WidthInBytes  = tmpParams.WidthInBytes;
        nodeParams->dstArray      = tmpParams.dstArray;
        nodeParams->dstDevice     = reinterpret_cast<mcDrvDeviceptr_t>(tmpParams.dstDevice);
        nodeParams->dstHeight     = tmpParams.dstHeight;
        nodeParams->dstHost       = tmpParams.dstHost;
        nodeParams->dstLOD        = tmpParams.dstLOD;
        nodeParams->dstMemoryType = tmpParams.dstMemoryType;
        nodeParams->dstPitch      = tmpParams.dstPitch;
        nodeParams->dstXInBytes   = tmpParams.dstXInBytes;
        nodeParams->dstY          = tmpParams.dstY;
        nodeParams->dstZ          = tmpParams.dstZ;
        nodeParams->reserved0     = tmpParams.reserved0;
        nodeParams->reserved1     = tmpParams.reserved1;
        nodeParams->srcArray      = tmpParams.srcArray;
        nodeParams->srcDevice     = reinterpret_cast<mcDrvDeviceptr_t>(tmpParams.srcDevice);
        nodeParams->srcHeight     = tmpParams.srcHeight;
        nodeParams->srcHost       = tmpParams.srcHost;
        nodeParams->srcLOD        = tmpParams.srcLOD;
        nodeParams->srcMemoryType = tmpParams.srcMemoryType;
        nodeParams->srcPitch      = tmpParams.srcPitch;
        nodeParams->srcXInBytes   = tmpParams.srcXInBytes;
        nodeParams->srcY          = tmpParams.srcY;
        nodeParams->srcZ          = tmpParams.srcZ;
    }

    return mcErrorTomcDrvError(err);
}

mcDrvError_t wcuGraphMemcpyNodeSetParams(mcDrvGraphNode hNode, const mcDrvMemcpy3D *nodeParams)
{
    if (validateMemoryType(nodeParams->srcMemoryType) == false ||
        validateMemoryType(nodeParams->dstMemoryType) == false) {
        return mcErrorTomcDrvError(mcErrorInvalidValue);
    }
    mcMemcpy3DParms params = getMemcpy3DParms(nodeParams);
    return mcErrorTomcDrvError(mcGraphMemcpyNodeSetParams(hNode, &params));
}

mcDrvError_t wcuGraphMemsetNodeGetParams(mcDrvGraphNode hNode, mcDrvMemsetNodeParams *nodeParams)
{
    mcMemsetParams params;
    mcError_t err = mcGraphMemsetNodeGetParams(hNode, &params);
    if (err == mcSuccess) {
        nodeParams->dst         = reinterpret_cast<unsigned long long>(params.dst);
        nodeParams->value       = params.value;
        nodeParams->elementSize = params.elementSize;
        nodeParams->height      = params.height;
        nodeParams->pitch       = params.pitch;
        nodeParams->width       = params.width;
    }
    return mcErrorTomcDrvError(err);
}

mcDrvError_t wcuGraphMemsetNodeSetParams(mcDrvGraphNode hNode,
                                         const mcDrvMemsetNodeParams *memsetParams)
{
    mcMemsetParams params;
    params.dst         = reinterpret_cast<void *>(memsetParams->dst);
    params.value       = memsetParams->value;
    params.elementSize = memsetParams->elementSize;
    params.pitch       = memsetParams->pitch;
    params.width       = memsetParams->width;
    params.height      = memsetParams->height;

    return mcErrorTomcDrvError(mcGraphMemsetNodeSetParams(hNode, &params));
}

mcDrvError_t wcuGraphNodeFindInClone(mcDrvGraphNode *phNode, mcDrvGraphNode hOriginalNode,
                                     mcDrvGraph hClonedGraph)
{

    return mcErrorTomcDrvError(mcGraphNodeFindInClone(phNode, hOriginalNode, hClonedGraph));
}

mcDrvError_t wcuGraphNodeGetDependencies(mcDrvGraphNode hNode, mcDrvGraphNode *dependencies,
                                         size_t *numDependencies)
{
    return mcErrorTomcDrvError(mcGraphNodeGetDependencies(hNode, dependencies, numDependencies));
}

mcDrvError_t wcuGraphNodeGetDependentNodes(mcDrvGraphNode hNode, mcDrvGraphNode *dependentNodes,
                                           size_t *numDependentNodes)
{
    return mcErrorTomcDrvError(
        mcGraphNodeGetDependentNodes(hNode, dependentNodes, numDependentNodes));
}

mcDrvError_t wcuGraphNodeGetEnabled(mcDrvGraphExec hGraphExec, mcDrvGraphNode hNode,
                                    unsigned int *isEnabled)
{
    return mcErrorTomcDrvError(mcGraphNodeGetEnabled(hGraphExec, hNode, isEnabled));
}

mcDrvError_t wcuGraphNodeGetType(mcDrvGraphNode hNode, mcDrvGraphNodeType *type)
{
    mcGraphNodeType hType;
    mcError_t err = mcGraphNodeGetType(hNode, &hType);
    if (err == mcSuccess) {
        switch (hType) {
        case mcGraphNodeTypeKernel:
            *type = MC_GRAPH_NODE_TYPE_KERNEL;
            break;
        case mcGraphNodeTypeMemcpy:
            *type = MC_GRAPH_NODE_TYPE_MEMCPY;
            break;
        case mcGraphNodeTypeMemset:
            *type = MC_GRAPH_NODE_TYPE_MEMSET;
            break;
        case mcGraphNodeTypeHost:
            *type = MC_GRAPH_NODE_TYPE_HOST;
            break;
        case mcGraphNodeTypeGraph:
            *type = MC_GRAPH_NODE_TYPE_GRAPH;
            break;
        case mcGraphNodeTypeEmpty:
            *type = MC_GRAPH_NODE_TYPE_EMPTY;
            break;
        case mcGraphNodeTypeWaitEvent:
            *type = MC_GRAPH_NODE_TYPE_WAIT_EVENT;
            break;
        case mcGraphNodeTypeEventRecord:
            *type = MC_GRAPH_NODE_TYPE_EVENT_RECORD;
            break;
        case mcGraphNodeTypeExtSemaphoreSignal:
            *type = MC_GRAPH_NODE_TYPE_EXT_SEMAS_SIGNAL;
            break;
        case mcGraphNodeTypeExtSemaphoreWait:
            *type = MC_GRAPH_NODE_TYPE_EXT_SEMAS_WAIT;
            break;
        case mcGraphNodeTypeMemAlloc:
            *type = MC_GRAPH_NODE_TYPE_MEM_ALLOC;
            break;
        case mcGraphNodeTypeMemFree:
            *type = MC_GRAPH_NODE_TYPE_MEM_FREE;
            break;
        case mcGraphNodeTypeBatchMemOp:
            *type = MC_GRAPH_NODE_TYPE_BATCH_MEM_OP;
            break;
        default:
            err = mcErrorInvalidValue;
            break;
        }
    }
    return mcErrorTomcDrvError(err);
}

mcDrvError_t wcuGraphNodeSetEnabled(mcDrvGraphExec hGraphExec, mcDrvGraphNode hNode,
                                    unsigned int isEnabled)
{

    return mcErrorTomcDrvError(mcGraphNodeSetEnabled(hGraphExec, hNode, isEnabled));
}

mcDrvError_t wcuGraphReleaseUserObject(mcDrvGraph graph, mcDrvUserObject object, unsigned int count)
{

    return mcErrorTomcDrvError(mcGraphReleaseUserObject(graph, object, count));
}

mcDrvError_t wcuGraphRemoveDependencies(mcDrvGraph hGraph, const mcDrvGraphNode *from,
                                        const mcDrvGraphNode *to, size_t numDependencies)
{
    return mcErrorTomcDrvError(mcGraphRemoveDependencies(hGraph, from, to, numDependencies));
}

mcDrvError_t wcuGraphRetainUserObject(mcDrvGraph graph, mcDrvUserObject object, unsigned int count,
                                      unsigned int flags)
{
    return mcErrorTomcDrvError(mcGraphRetainUserObject(graph, object, count, flags));
}

mcDrvError_t wcuGraphUpload(mcDrvGraphExec hGraphExec, mcDrvStream_t hStream)
{
    return mcErrorTomcDrvError(mcGraphUpload(hGraphExec, hStream));
}

mcDrvError_t wcuUserObjectCreate(mcDrvUserObject *object_out, void *ptr, mcHostFn_t destroy,
                                 unsigned int initialRefcount, unsigned int flags)
{
    return mcErrorTomcDrvError(
        mcUserObjectCreate(object_out, ptr, destroy, initialRefcount, flags));
}

mcDrvError_t wcuUserObjectRelease(mcDrvUserObject object, unsigned int count)
{
    return mcErrorTomcDrvError(mcUserObjectRelease(object, count));
}

mcDrvError_t wcuUserObjectRetain(mcDrvUserObject object, unsigned int count)
{
    return mcErrorTomcDrvError(mcUserObjectRetain(object, count));
}

mcDrvError_t wcuGraphAddBatchMemOpNode(mcDrvGraphNode *phGraphNode, mcDrvGraph hGraph,
                                       const mcDrvGraphNode *dependencies, size_t numDependencies,
                                       const mcDrvBatchMemOpNodeParams *nodeParams)
{
    return mcErrorTomcDrvError(
        mcGraphAddBatchMemOpNode(phGraphNode, hGraph, dependencies, numDependencies, nodeParams));
}

mcDrvError_t wcuGraphBatchMemOpNodeGetParams(mcDrvGraphNode hNode,
                                             mcDrvBatchMemOpNodeParams *nodeParams_out)
{
    return mcErrorTomcDrvError(mcGraphBatchMemOpNodeGetParams(hNode, nodeParams_out));
}

mcDrvError_t wcuGraphBatchMemOpNodeSetParams(mcDrvGraphNode hNode,
                                             const mcDrvBatchMemOpNodeParams *nodeParams)
{
    return mcErrorTomcDrvError(mcGraphBatchMemOpNodeSetParams(hNode, nodeParams));
}

mcDrvError_t wcuGraphExecBatchMemOpNodeSetParams(mcDrvGraphExec hGraphExec, mcDrvGraphNode hNode,
                                                 const mcDrvBatchMemOpNodeParams *nodeParams)
{
    return mcErrorTomcDrvError(mcGraphExecBatchMemOpNodeSetParams(hGraphExec, hNode, nodeParams));
}

//---------------------------------------------------------------------------//
// Graphics Interoperability
//---------------------------------------------------------------------------//
mcDrvError_t wcuGraphicsMapResources(unsigned int count, mcDrvGraphicsResource *resources,
                                     mcDrvStream_t hStream)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuGraphicsResourceGetMappedMipmappedArray(mcDrvMipmappedArray *pMipmappedArray,
                                                        mcDrvGraphicsResource resource)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuGraphicsResourceGetMappedPointer(mcDrvDeviceptr_t *pDevPtr, size_t *pSize,
                                                 mcDrvGraphicsResource resource)
{
    return MC_ERROR_NOT_SUPPORTED;
}
mcDrvError_t wcuGraphicsResourceSetMapFlags(mcDrvGraphicsResource resource, unsigned int flags)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuGraphicsSubResourceGetMappedArray(MCarray *pArray, mcDrvGraphicsResource resource,
                                                  unsigned int arrayIndex, unsigned int mipLevel)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuGraphicsUnmapResources(unsigned int count, mcDrvGraphicsResource *resources,
                                       mcDrvStream_t hStream)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuGraphicsUnregisterResource(mcDrvGraphicsResource resource)
{
    return MC_ERROR_NOT_SUPPORTED;
}

//---------------------------------------------------------------------------//
// Texture Reference Management
//---------------------------------------------------------------------------//
mcDrvError_t wcuTexRefSetArray(mcDrvTexref hTexRef, MCarray hArray, unsigned int Flags)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefSetMipmappedArray(mcDrvTexref hTexRef, mcDrvMipmappedArray hMipmappedArray,
                                        unsigned int Flags)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefSetAddress(size_t *ByteOffset, mcDrvTexref hTexRef, mcDrvDeviceptr_t dptr,
                                 size_t bytes)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefSetAddress2D(mcDrvTexref hTexRef, const mcDrvArrayDescriptor *desc,
                                   mcDrvDeviceptr_t dptr, size_t Pitch)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefSetFormat(mcDrvTexref hTexRef, mcArray_Format fmt, int NumPackedComponents)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefSetAddressMode(mcDrvTexref hTexRef, int dim, mcDrvAddress_mode am)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefSetFilterMode(mcDrvTexref hTexRef, mcDrvFilter_mode fm)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefSetMipmapFilterMode(mcDrvTexref hTexRef, mcDrvFilter_mode fm)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefSetMipmapLevelBias(mcDrvTexref hTexRef, float bias)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefSetMipmapLevelClamp(mcDrvTexref hTexRef, float minMipmapLevelClamp,
                                          float maxMipmapLevelClamp)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefSetMaxAnisotropy(mcDrvTexref hTexRef, unsigned int maxAniso)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefSetBorderColor(mcDrvTexref hTexRef, float *pBorderColor)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefSetFlags(mcDrvTexref hTexRef, unsigned int Flags)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefGetAddress(mcDrvDeviceptr_t *pdptr, mcDrvTexref hTexRef)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefGetArray(MCarray *phArray, mcDrvTexref hTexRef)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefGetMipmappedArray(mcDrvMipmappedArray *phMipmappedArray, mcDrvTexref hTexRef)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefGetAddressMode(mcDrvAddress_mode *pam, mcDrvTexref hTexRef, int dim)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefGetFilterMode(mcDrvFilter_mode *pfm, mcDrvTexref hTexRef)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefGetMipmapFilterMode(mcDrvFilter_mode *pfm, mcDrvTexref hTexRef)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefGetMipmapLevelBias(float *pbias, mcDrvTexref hTexRef)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefGetMipmapLevelClamp(float *pminMipmapLevelClamp, float *pmaxMipmapLevelClamp,
                                          mcDrvTexref hTexRef)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefGetMaxAnisotropy(int *pmaxAniso, mcDrvTexref hTexRef)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefGetBorderColor(float *pBorderColor, mcDrvTexref hTexRef)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefGetFlags(unsigned int *pFlags, mcDrvTexref hTexRef)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefGetFormat(mcArray_Format *pFormat, int *pNumChannels, mcDrvTexref hTexRef)
{
    /* TODO:wcuda_skipped - for deprecated */
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuTexRefCreate(mcDrvTexref *pTexRef) { return MC_ERROR_NOT_SUPPORTED; }

mcDrvError_t wcuTexRefDestroy(mcDrvTexref hTexRef) { return MC_ERROR_NOT_SUPPORTED; }

//---------------------------------------------------------------------------//
// Texture Object Management
//---------------------------------------------------------------------------//
mcDrvError_t wcuTexObjectCreate(mcDrvTexObject *pTexObject, const mcDrvResourceDesc *pResDesc,
                                const mcDrvTextureDesc *pTexDesc,
                                const mcDrvResourceViewDesc *pResViewDesc)
{

    if (pTexObject == nullptr || pResDesc == nullptr || pTexDesc == nullptr) {
        return MC_ERROR_INVALID_VALUE;
    }

    mcResourceDesc resDesc = getResourceDesc(*pResDesc);
    mcTextureDesc texDesc  = getTextureDesc(*pTexDesc);

    mcTextureObject_t texObject;
    mcError_t ret = mcSuccess;

    if (pResViewDesc != nullptr) {
        mcResourceViewDesc resViewDesc = getResourceViewDesc(*pResViewDesc);
        ret = mcCreateTextureObject_v0(&texObject, &resDesc, &texDesc, &resViewDesc);
    } else {
        ret = mcCreateTextureObject_v0(&texObject, &resDesc, &texDesc, nullptr);
    }

    if (ret == mcSuccess) {
        *pTexObject = reinterpret_cast<mcDrvTexObject>(texObject);
    }

    return mcErrorTomcDrvError(ret);
}

mcDrvError_t wcuTexObjectDestroy(mcDrvTexObject texObject)
{
    mcTextureObject_t mcTexObject = reinterpret_cast<mcTextureObject_t>(texObject);

    if (mcTexObject == nullptr) {
        return MC_ERROR_INVALID_VALUE;
    }

    return mcErrorTomcDrvError(mcDestroyTextureObject(mcTexObject));
}

mcDrvError_t wcuTexObjectGetResourceDesc(mcDrvResourceDesc *pResDesc, mcDrvTexObject texObject)
{
    if (pResDesc == nullptr || texObject == 0) {
        return MC_ERROR_INVALID_VALUE;
    }

    mcTextureObject_t mcTexObject = reinterpret_cast<mcTextureObject_t>(texObject);
    mcResourceDesc resDesc;

    auto ret = mcGetTextureObjectResourceDesc(&resDesc, mcTexObject);

    if (ret != mcSuccess) {
        return mcErrorTomcDrvError(ret);
    }

    *pResDesc = getResourceDesc(resDesc);

    return MC_SUCCESS;
}

mcDrvError_t wcuTexObjectGetTextureDesc(mcDrvTextureDesc *pTexDesc, mcDrvTexObject texObject)
{
    if (pTexDesc == nullptr || texObject == 0) {
        return MC_ERROR_INVALID_VALUE;
    }

    mcTextureObject_t mcTexObject = reinterpret_cast<mcTextureObject_t>(texObject);
    mcTextureDesc texDesc;

    auto ret = mcGetTextureObjectTextureDesc(&texDesc, mcTexObject);

    if (ret != mcSuccess) {
        return mcErrorTomcDrvError(ret);
    }

    *pTexDesc = getTextureDesc(texDesc);

    return MC_SUCCESS;
}

mcDrvError_t wcuTexObjectGetResourceViewDesc(mcDrvResourceViewDesc *pResViewDesc,
                                             mcDrvTexObject texObject)
{
    if (pResViewDesc == nullptr || texObject == 0) {
        return MC_ERROR_INVALID_VALUE;
    }

    mcTextureObject_t mcTexObject = reinterpret_cast<mcTextureObject_t>(texObject);
    mcResourceViewDesc resViewDesc;

    auto ret = mcGetTextureObjectResourceViewDesc(&resViewDesc, mcTexObject);

    if (ret != mcSuccess) {
        return mcErrorTomcDrvError(ret);
    }

    *pResViewDesc = getResourceViewDesc(resViewDesc);

    return MC_SUCCESS;
}

//---------------------------------------------------------------------------//
// Surface Reference Management
//---------------------------------------------------------------------------//
mcDrvError_t wcuSurfRefSetArray(mcDrvSurfref hSurfRef, MCarray hArray, unsigned int Flags)
{
    return MC_ERROR_NOT_SUPPORTED;
}

mcDrvError_t wcuSurfRefGetArray(MCarray *phArray, mcDrvSurfref hSurfRef)
{
    return MC_ERROR_NOT_SUPPORTED;
}

//---------------------------------------------------------------------------//
// Surface Object Management
//---------------------------------------------------------------------------//
mcDrvError_t wcuSurfObjectCreate(mcDrvSurfObject *pSurfObject, const mcDrvResourceDesc *pResDesc)
{
    /* TODO:wcuda_skipped - for deprecated */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

mcDrvError_t wcuSurfObjectDestroy(mcDrvSurfObject surfObject)
{
    /* TODO:wcuda_skipped - for deprecated */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}
mcDrvError_t wcuSurfObjectGetResourceDesc(mcDrvResourceDesc *pResDesc, mcDrvSurfObject surfObject)
{
    /* TODO:wcuda_skipped - for deprecated */
    return mcErrorTomcDrvError(mcErrorNotYetImplemented);
}

std::map<std::string, std::map<unsigned int, void *>> cuApiWrapperMap = {
    /* Error Handling */
    {"cuGetErrorName", {{0, (void *)wcuGetErrorName}}},
    {"cuGetErrorString", {{0, (void *)wcuGetErrorString}}},

    /* Initialization */
    {"cuInit", {{0, (void *)wcuInit}}},

    /* Version Management */
    {"cuDriverGetVersion", {{0, (void *)wcuDriverGetVersion}}},

    /* Device Management */
    {"cuDeviceGetAttribute", {{0, (void *)wcuDeviceGetAttribute}}},
    {"cuDeviceGetUuid", {{0, (void *)wcuDeviceGetUuid}}},
    {"cuDeviceGetUuid_v2", {{0, (void *)wcuDeviceGetUuid_v2}}},
    {"cuDeviceGetCount", {{0, (void *)wcuDeviceGetCount}}},
    {"cuDeviceGetByPCIBusId", {{0, (void *)wcuDeviceGetByPCIBusId}}},
    {"cuDeviceGetPCIBusId", {{0, (void *)wcuDeviceGetPCIBusId}}},
    {"cuDeviceGet", {{0, (void *)wcuDeviceGet}}},
    {"cuDeviceGetName", {{0, (void *)wcuDeviceGetName}}},
    {"cuDeviceTotalMem", {{0, (void *)wcuDeviceTotalMem}}},
    {"cuDeviceGetDefaultMemPool", {{0, (void *)wcuDeviceGetDefaultMemPool}}},
    {"cuDeviceGetMemPool", {{0, (void *)wcuDeviceGetMemPool}}},
    {"cuDeviceSetMemPool", {{0, (void *)wcuDeviceSetMemPool}}},
    {"cuDeviceGetLuid", {{0, (void *)wcuDeviceGetLuid}}},
    {"cuDeviceGetP2PAttribute", {{0, (void *)wcuDeviceGetP2PAttribute}}},
    {"cuFlushGPUDirectRDMAWrites", {{0, (void *)wcuFlushGPUDirectRDMAWrites}}},
    {"cuDeviceGetNvSciSyncAttributes", {{0, (void *)wcuDeviceGetNvSciSyncAttributes}}},

    /* Primary Context Management */
    {"cuDevicePrimaryCtxGetState", {{0, (void *)wcuDevicePrimaryCtxGetState}}},
    {"cuDevicePrimaryCtxRelease", {{0, (void *)wcuDevicePrimaryCtxRelease}}},
    {"cuDevicePrimaryCtxRetain", {{0, (void *)wcuDevicePrimaryCtxRetain}}},
    {"cuDevicePrimaryCtxSetFlags", {{0, (void *)wcuDevicePrimaryCtxSetFlags}}},
    {"cuDevicePrimaryCtxReset", {{0, (void *)wcuDevicePrimaryCtxReset}}},

    /* Context Management */
    {"cuCtxCreate", {{0, (void *)wcuCtxCreate}}},
    {"cuCtxCreate_v3", {{0, (void *)wcuCtxCreate_v3}}},
    {"cuCtxDestroy", {{0, (void *)wcuCtxDestroy}}},
    {"cuCtxGetApiVersion", {{0, (void *)wcuCtxGetApiVersion}}},
    {"cuCtxGetCacheConfig", {{0, (void *)wcuCtxGetCacheConfig}}},
    {"cuCtxGetCurrent", {{0, (void *)wcuCtxGetCurrent}}},
    {"cuCtxGetDevice", {{0, (void *)wcuCtxGetDevice}}},
    {"cuCtxGetExecAffinity", {{0, (void *)wcuCtxGetExecAffinity}}},
    {"cuCtxGetFlags", {{0, (void *)wcuCtxGetFlags}}},
    {"cuCtxGetLimit", {{0, (void *)wcuCtxGetLimit}}},
    {"cuCtxGetSharedMemConfig", {{0, (void *)wcuCtxGetSharedMemConfig}}},
    {"cuCtxGetStreamPriorityRange", {{0, (void *)wcuCtxGetStreamPriorityRange}}},
    {"cuCtxPopCurrent", {{0, (void *)wcuCtxPopCurrent}}},
    {"cuCtxPushCurrent", {{0, (void *)wcuCtxPushCurrent}}},
    {"cuCtxResetPersistingL2Cache", {{0, (void *)wcuCtxResetPersistingL2Cache}}},
    {"cuCtxSetCacheConfig", {{0, (void *)wcuCtxSetCacheConfig}}},
    {"cuCtxSetCurrent", {{0, (void *)wcuCtxSetCurrent}}},
    {"cuCtxSetLimit", {{0, (void *)wcuCtxSetLimit}}},
    {"cuCtxSetSharedMemConfig", {{0, (void *)wcuCtxSetSharedMemConfig}}},
    {"cuCtxSynchronize", {{0, (void *)wcuCtxSynchronize}}},

    /* Module Management */
    {"cuModuleLoad", {{0, (void *)wcuModuleLoad}}},
    {"cuModuleLoadData", {{0, (void *)wcuModuleLoadData}}},
    {"cuModuleLoadDataEx", {{0, (void *)wcuModuleLoadDataEx}}},
    {"cuModuleUnload", {{0, (void *)wcuModuleUnload}}},
    {"cuModuleGetFunction", {{0, (void *)wcuModuleGetFunction}}},
    {"cuLinkCreate", {{0, (void *)wcuLinkCreate}}},
    {"cuLinkAddData", {{0, (void *)wcuLinkAddData}}},
    {"cuLinkComplete", {{0, (void *)wcuLinkComplete}}},
    {"cuLinkAddFile", {{0, (void *)wcuLinkAddFile}}},
    {"cuLinkDestroy", {{0, (void *)wcuLinkDestroy}}},
    {"cuModuleGetGlobal", {{0, (void *)wcuModuleGetGlobal}}},
    {"cuModuleLoadFatBinary", {{0, (void *)wcuModuleLoadFatBinary}}},

    /* Memory Management */
    {"cuMemAlloc", {{0, (void *)wcuMemAlloc}}},
    {"cuMemAllocHost", {{0, (void *)wcuMemAllocHost}}},
    {"cuMemAllocManaged", {{0, (void *)wcuMemAllocManaged}}},
    {"cuMemAllocPitch", {{0, (void *)wcuMemAllocPitch}}},
    {"cuMemFree", {{0, (void *)wcuMemFree}}},
    {"cuMemFreeHost", {{0, (void *)wcuMemFreeHost}}},
    {"cuMemHostAlloc", {{0, (void *)wcuMemHostAlloc}}},
    {"cuMemHostGetDevicePointer", {{0, (void *)wcuMemHostGetDevicePointer}}},
    {"cuMemHostGetFlags", {{0, (void *)wcuMemHostGetFlags}}},
    {"cuMemHostRegister", {{0, (void *)wcuMemHostRegister}}},
    {"cuMemHostUnregister", {{0, (void *)wcuMemHostUnregister}}},
    {"cuMemcpy", {{0, (void *)wcuMemcpy}}},
    {"cuMemcpy2D", {{0, (void *)wcuMemcpy2D}}},
    {"cuMemcpy2DUnaligned", {{0, (void *)wcuMemcpy2DUnaligned}}},
    {"cuMemcpy2DAsync", {{0, (void *)wcuMemcpy2DAsync}}},
    {"cuMemcpyAsync", {{0, (void *)wcuMemcpyAsync}}},
    {"cuMemGetInfo", {{0, (void *)wcuMemGetInfo}}},
    {"cuMemGetAddressRange", {{0, (void *)wcuMemGetAddressRange}}},
    {"cuMemsetD16", {{0, (void *)wcuMemsetD16}}},
    {"cuMemsetD16Async", {{0, (void *)wcuMemsetD16Async}}},
    {"cuMemsetD32", {{0, (void *)wcuMemsetD32}}},
    {"cuMemsetD32Async", {{0, (void *)wcuMemsetD32Async}}},
    {"cuMemsetD8Async", {{0, (void *)wcuMemsetD8Async}}},
    {"cuMemsetD8", {{0, (void *)wcuMemsetD8}}},
    {"cuMemsetD2D8", {{0, (void *)wcuMemsetD2D8}}},
    {"cuMemsetD2D8Async", {{0, (void *)wcuMemsetD2D8Async}}},
    {"cuMemsetD2D16", {{0, (void *)wcuMemsetD2D16}}},
    {"cuMemsetD2D16Async", {{0, (void *)wcuMemsetD2D16Async}}},
    {"cuMemsetD2D32", {{0, (void *)wcuMemsetD2D32}}},
    {"cuMemsetD2D32Async", {{0, (void *)wcuMemsetD2D32Async}}},
    {"cuMemcpyDtoD", {{0, (void *)wcuMemcpyDtoD}}},
    {"cuMemcpyDtoDAsync", {{0, (void *)wcuMemcpyDtoDAsync}}},
    {"cuMemcpyDtoH", {{0, (void *)wcuMemcpyDtoH}}},
    {"cuMemcpyDtoHAsync", {{0, (void *)wcuMemcpyDtoHAsync}}},
    {"cuMemcpyHtoD", {{0, (void *)wcuMemcpyHtoD}}},
    {"cuMemcpyHtoDAsync", {{0, (void *)wcuMemcpyHtoDAsync}}},
    {"cuMemcpyPeer", {{0, (void *)wcuMemcpyPeer}}},
    {"cuMemcpyPeerAsync", {{0, (void *)wcuMemcpyPeerAsync}}},

    /* Virtual Memory Management */
    {"cuMemAddressFree", {{0, (void *)wcuMemAddressFree}}},
    {"cuMemAddressReserve", {{0, (void *)wcuMemAddressReserve}}},
    {"cuMemMap", {{0, (void *)wcuMemMap}}},
    {"cuMemUnmap", {{0, (void *)wcuMemUnmap}}},
    {"cuMemSetAccess", {{0, (void *)wcuMemSetAccess}}},
    {"cuMemGetAccess", {{0, (void *)wcuMemGetAccess}}},
    {"cuMemExportToShareableHandle", {{0, (void *)wcuMemExportToShareableHandle}}},
    {"cuMemImportFromShareableHandle", {{0, (void *)wcuMemImportFromShareableHandle}}},
    {"cuMemGetAllocationGranularity", {{0, (void *)wcuMemGetAllocationGranularity}}},
    {"cuMemGetAllocationPropertiesFromHandle",
     {{0, (void *)wcuMemGetAllocationPropertiesFromHandle}}},
    {"cuMemRetainAllocationHandle", {{0, (void *)wcuMemRetainAllocationHandle}}},
    {"cuMemCreate", {{0, (void *)wcuMemCreate}}},
    {"cuMemRelease", {{0, (void *)wcuMemRelease}}},

    /* Multicast Object Management */
    {"cuMulticastCreate", {{0, (void *)wcuMulticastCreate}}},
    {"cuMulticastAddDevice", {{0, (void *)wcuMulticastAddDevice}}},
    {"cuMulticastBindMem", {{0, (void *)wcuMulticastBindMem}}},
    {"cuMulticastBindAddr", {{0, (void *)wcuMulticastBindAddr}}},
    {"cuMulticastUnbind", {{0, (void *)wcuMulticastUnbind}}},
    {"cuMulticastGetGranularity", {{0, (void *)wcuMulticastGetGranularity}}},

    /* Stream Management */
    {"cuStreamCreate", {{0, (void *)wcuStreamCreate}}},
    {"cuStreamCreateWithPriority", {{0, (void *)wcuStreamCreateWithPriority}}},
    {"cuStreamDestroy", {{0, (void *)wcuStreamDestroy}}},
    {"cuStreamGetFlags", {{0, (void *)wcuStreamGetFlags}}},
    {"cuStreamGetPriority", {{0, (void *)wcuStreamGetPriority}}},
    {"cuStreamQuery", {{0, (void *)wcuStreamQuery}}},
    {"cuStreamSynchronize", {{0, (void *)wcuStreamSynchronize}}},
    {"cuStreamWaitEvent", {{0, (void *)wcuStreamWaitEvent}}},
    {"cuStreamAddCallback", {{0, (void *)wcuStreamAddCallback}}},
    {"cuStreamAttachMemAsync", {{0, (void *)wcuStreamAttachMemAsync}}},
    {"cuStreamCopyAttributes", {{0, (void *)wcuStreamCopyAttributes}}},
    {"cuStreamSetAttribute", {{0, (void *)wcuStreamSetAttribute}}},
    {"cuStreamGetAttribute", {{0, (void *)wcuStreamGetAttribute}}},
    {"cuStreamGetCtx", {{0, (void *)wcuStreamGetCtx}}},

    /* Unified Addressing */
    {"cuMemAdvise", {{0, (void *)wcuMemAdvise}}},
    {"cuPointerGetAttribute", {{0, (void *)wcuPointerGetAttribute}}},
    {"cuPointerGetAttributes", {{0, (void *)wcuPointerGetAttributes}}},
    {"cuMemPrefetchAsync", {{0, (void *)wcuMemPrefetchAsync}}},
    {"cuMemRangeGetAttribute", {{0, (void *)wcuMemRangeGetAttribute}}},
    {"cuMemRangeGetAttributes", {{0, (void *)wcuMemRangeGetAttributes}}},
    {"cuPointerSetAttribute", {{0, (void *)wcuPointerSetAttribute}}},

    /* Event Management */
    {"cuIpcGetEventHandle", {{0, (void *)wcuIpcGetEventHandle}}},
    {"cuIpcOpenEventHandle", {{0, (void *)wcuIpcOpenEventHandle}}},
    {"cuEventCreate", {{0, (void *)wcuEventCreate}}},
    {"cuEventDestroy", {{0, (void *)wcuEventDestroy}}},
    {"cuEventElapsedTime", {{0, (void *)wcuEventElapsedTime}}},
    {"cuEventQuery", {{0, (void *)wcuEventQuery}}},
    {"cuEventRecord", {{0, (void *)wcuEventRecord}}},
    {"cuEventRecordWithFlags", {{0, (void *)wcuEventRecordWithFlags}}},
    {"cuEventSynchronize", {{0, (void *)wcuEventSynchronize}}},

    /* Execution Control */
    {"cuFuncGetAttribute", {{0, (void *)wcuFuncGetAttribute}}},
    {"cuLaunchKernel", {{0, (void *)wcuLaunchKernel}}},
    {"cuFuncGetModule", {{0, (void *)wcuFuncGetModule}}},
    {"cuFuncSetAttribute", {{0, (void *)wcuFuncSetAttribute}}},
    {"cuFuncSetCacheConfig", {{0, (void *)wcuFuncSetCacheConfig}}},
    {"cuFuncSetSharedMemConfig", {{0, (void *)wcuFuncSetSharedMemConfig}}},
    {"cuLaunchCooperativeKernel", {{0, (void *)wcuLaunchCooperativeKernel}}},
    {"cuLaunchHostFunc", {{0, (void *)wcuLaunchHostFunc}}},

    /* Peer Context Memory Access */
    {"cuDeviceCanAccessPeer", {{0, (void *)wcuDeviceCanAccessPeer}}},
    {"cuCtxEnablePeerAccess", {{0, (void *)wcuCtxEnablePeerAccess}}},
    {"cuCtxDisablePeerAccess", {{0, (void *)wcuCtxDisablePeerAccess}}},

    /* Profiler Control */
    {"cuProfilerInitialize", {{0, (void *)wcuProfilerInitialize}}},
    {"cuProfilerStart", {{0, (void *)wcuProfilerStart}}},
    {"cuProfilerStop", {{0, (void *)wcuProfilerStop}}},

    /* Driver Entry Point Access */
    {"cuGetProcAddress", {{0, (void *)wcuGetProcAddress}}},

    /* Stream Ordered Memory Allocator */
    {"cuMemAllocAsync", {{0, (void *)wcuMemAllocAsync}}},
    {"cuMemAllocFromPoolAsync", {{0, (void *)wcuMemAllocFromPoolAsync}}},
    {"cuMemFreeAsync", {{0, (void *)wcuMemFreeAsync}}},
    {"cuMemPoolCreate", {{0, (void *)wcuMemPoolCreate}}},
    {"cuMemPoolDestroy", {{0, (void *)wcuMemPoolDestroy}}},
    {"cuMemPoolExportPointer", {{0, (void *)wcuMemPoolExportPointer}}},
    {"cuMemPoolExportToShareableHandle", {{0, (void *)wcuMemPoolExportToShareableHandle}}},
    {"cuMemPoolImportFromShareableHandle", {{0, (void *)wcuMemPoolImportFromShareableHandle}}},
    {"cuMemPoolImportPointer", {{0, (void *)wcuMemPoolImportPointer}}},
    {"cuMemPoolGetAccess", {{0, (void *)wcuMemPoolGetAccess}}},
    {"cuMemPoolGetAttribute", {{0, (void *)wcuMemPoolGetAttribute}}},
    {"cuMemPoolSetAccess", {{0, (void *)wcuMemPoolSetAccess}}},
    {"cuMemPoolSetAttribute", {{0, (void *)wcuMemPoolSetAttribute}}},
    {"cuMemPoolTrimTo", {{0, (void *)wcuMemPoolTrimTo}}},

    /* Stream Memory Operations */
    {"cuStreamBatchMemOp", {{0, (void *)wcuStreamBatchMemOp}}},
    {"cuStreamWaitValue32", {{0, (void *)wcuStreamWaitValue32}}},
    {"cuStreamWaitValue64", {{0, (void *)wcuStreamWaitValue64}}},
    {"cuStreamWriteValue32", {{0, (void *)wcuStreamWriteValue32}}},
    {"cuStreamWriteValue64", {{0, (void *)wcuStreamWriteValue64}}},

    /* Occupancy */
    {"cuOccupancyAvailableDynamicSMemPerBlock",
     {{0, (void *)wcuOccupancyAvailableDynamicSMemPerBlock}}},
    {"cuOccupancyMaxActiveBlocksPerMultiprocessor",
     {{0, (void *)wcuOccupancyMaxActiveBlocksPerMultiprocessor}}},
    {"cuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags",
     {{0, (void *)wcuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags}}},
    {"cuOccupancyMaxPotentialBlockSize", {{0, (void *)wcuOccupancyMaxPotentialBlockSize}}},
    {"cuOccupancyMaxPotentialBlockSizeWithFlags",
     {{0, (void *)wcuOccupancyMaxPotentialBlockSizeWithFlags}}},
};
